/*
 * PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
 *
 * Authors: Sumana Srinivasan, NeXT Inc.;            sumana_srinivasan@next.com
 *          Terence Parr, Parr Research Corporation; parrt@parr-research.com
 *          Russell Quong, Purdue University;        quong@ecn.purdue.edu
 *
 * VERSION 1.2
 *
 * SOFTWARE RIGHTS
 *
 * This file is a part of the ANTLR-based C++ grammar and is free
 * software.  We do not reserve any LEGAL rights to its use or
 * distribution, but you may NOT claim ownership or authorship of this
 * grammar or support code.  An individual or company may otherwise do
 * whatever they wish with the grammar distributed herewith including the
 * incorporation of the grammar or the output generated by ANTLR into
 * commerical software.  You may redistribute in source or binary form
 * without payment of royalties to us as long as this header remains
 * in all source distributions.
 *
 * We encourage users to develop parsers/tools using this grammar.
 * In return, we ask that credit is given to us for developing this
 * grammar.  By "credit", we mean that if you incorporate our grammar or
 * the generated code into one of your programs (commercial product,
 * research project, or otherwise) that you acknowledge this fact in the
 * documentation, research report, etc....  In addition, you should say nice
 * things about us at every opportunity.
 *
 * As long as these guidelines are kept, we expect to continue enhancing
 * this grammar.  Feel free to send us enhancements, fixes, bug reports,
 * suggestions, or general words of encouragement at parrt@parr-research.com.
 * 
 * NeXT Computer Inc.
 * 900 Chesapeake Dr.
 * Redwood City, CA 94555
 * 12/02/1994
 * 
 * Restructured for public consumption by Terence Parr late February, 1995.
 *
 * DISCLAIMER: we make no guarantees that this grammar works, makes sense,
 *             or can be used to do anything useful.
 */
/* 2001-2002
 * Version 1.0
 * This C++ grammar file has been converted from PCCTS to run under 
 *  ANTLR to generate lexer and parser in C++ code by
 *  Jianguo Zuo and David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 */
/* 2003
 * Version 2.0 was published by David Wigg in September 2003
 */
/* 2004
 * Version 3.0 July 2004
 * This is version 3.0 of the C++ grammar definition for ANTLR to 
 *  generate lexer and parser in C++ code updated by
 *  David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 * wiggjd@bcs.ac.uk
 * blackse@lsbu.ac.uk
 *
 * See MyReadMe.txt for further information
 *
 * This file is best viewed in courier font with tabs set to 4 spaces
 */

/* 2005
 * Some modifications were made by Gordon Prieur (Gordon.Prieur@sun.com);
 * after that the grammar was ported to Java by Vladimir Kvashin (Vladimir.Kvashin@sun.com)
 *
 * NOCDDL
 */

header {

package org.netbeans.modules.cnd.modelimpl.parser.generated;

import java.io.*;
import java.util.*;

import org.netbeans.modules.cnd.antlr.*;
import org.netbeans.modules.cnd.antlr.collections.*;
import org.netbeans.modules.cnd.antlr.debug.misc.*;
import org.netbeans.modules.cnd.modelimpl.parser.*;
import org.netbeans.modules.cnd.modelimpl.parser.Enum;
import org.netbeans.modules.cnd.modelimpl.debug.*;

}

options {
	language = "Java";
} 

{
@SuppressWarnings({"unchecked", "cast", "fallthrough"})
}
class CPPParser extends Parser;

options {
	k = 2;
	importVocab = APT;
	exportVocab = CPP;
	codeGenMakeSwitchThreshold = 2;
	codeGenBitsetTestThreshold = 3;
	noConstructors = true;
	buildAST = true;
        genASTClassMap = false;
}

//
// We create CsmAST node for each token,
// which isn't dummy - i.e. which has an appropriate text in translation unit.
// Examples are  CSM_USING_DIRECTIVE and CSM_USING_DECLARATION
//
tokens {
        CSM_START<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>; // dummy token - should be BEFORE ALL CSM_...

	CSM_TRANSLATION_UNIT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_CLASS_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_ENUM_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_ENUM_FWD_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_NAMESPACE_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.NamedFakeAST>;
	CSM_CTOR_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_CTOR_TEMPLATE_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FUNCTION_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FUNCTION_LIKE_VARIABLE_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FUNCTION_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FUNCTION_RET_FUN_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FUNCTION_RET_FUN_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FUNCTION_TEMPLATE_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FUNCTION_TEMPLATE_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_PARAMETER_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TYPE_BUILTIN<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
        CSM_TYPE_DECLTYPE<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TYPE_COMPOUND<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_TEMPLATE_EXPLICIT_SPECIALIZATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FWD_TEMPLATE_EXPLICIT_SPECIALIZATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TEMPLATE_EXPLICIT_INSTANTIATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TEMPLATE_CTOR_DEFINITION_EXPLICIT_SPECIALIZATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TEMPLATE_DTOR_DEFINITION_EXPLICIT_SPECIALIZATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TEMPLATE_FUNCTION_DEFINITION_EXPLICIT_SPECIALIZATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
        CSM_USER_TYPE_CAST_DEFINITION_EXPLICIT_SPECIALIZATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TEMPLATE_CLASS_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_EXTERN_TEMPLATE<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_TEMPLATE_TEMPLATE_PARAMETER<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_DTOR_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_DTOR_TEMPLATE_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_DTOR_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_CTOR_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_CTOR_TEMPLATE_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_USER_TYPE_CAST_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_USER_TYPE_CAST_TEMPLATE_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_USER_TYPE_CAST_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_USER_TYPE_CAST_TEMPLATE_DEFINITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_GENERIC_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	
	CSM_TEMPL_FWD_CL_OR_STAT_MEM<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_STRANGE_2<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FIELD<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_VISIBILITY_REDEF<AST=org.netbeans.modules.cnd.modelimpl.parser.NamedFakeAST>;
	
	CSM_TEMPLATE_PARMLIST<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_PARMLIST<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_KR_PARMLIST<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	
	CSM_ENUMERATOR_LIST<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_NAMESPACE_ALIAS<AST=org.netbeans.modules.cnd.modelimpl.parser.NamedFakeAST>;
	CSM_USING_DIRECTIVE<AST=org.netbeans.modules.cnd.modelimpl.parser.NamedFakeAST>;
	CSM_USING_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.NamedFakeAST>;

        CSM_CTOR_INITIALIZER<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
        CSM_CTOR_INITIALIZER_LIST<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_QUALIFIED_ID<AST=org.netbeans.modules.cnd.modelimpl.parser.NamedFakeAST>;

	////////// STATEMENTS //////////

	// This is just a start marker of the token types, related with statements
	// Do NOT create tokens of this type
	// Place token types, which correspond to statements only AFTER this type
	// (but BEFORE CSM_STATEMENTS_END)
	CSM_STATEMENTS_START<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_LABELED_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_CASE_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_DEFAULT_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_EXPRESSION_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_DECLARATION_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_COMPOUND_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
    CSM_COMPOUND_STATEMENT_LAZY<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
    CSM_TRY_CATCH_STATEMENT_LAZY<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	// selection
	CSM_IF_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_SWITCH_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	// iteration
	CSM_WHILE_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_DO_WHILE_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_FOR_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	// jump
	CSM_GOTO_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_CONTINUE_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_BREAK_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_RETURN_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	// try-catch
    CSM_TRY_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
    CSM_CATCH_CLAUSE<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_THROW_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_ASM_BLOCK<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	// This is just an end marker of the token types, related with statements
	// Do NOT create tokens of this type
	// Place token types, which correspond to statements only BEFORE this type
	// (but AFTER CSM_STATEMENTS_START)
	CSM_STATEMENTS_END<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	////////// EXPRESSIONS //////////

	// This is just a start marker of the token types, related with expressions
	// Do NOT create tokens of this type
	// Place token types, which correspond to expressions only AFTER this type
	// (but BEFORE CSM_EXPRESSIONS_END)
	CSM_EXPRESSIONS_START<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	// temporary solution
	// to wrap all expressions 
	CSM_EXPRESSION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

        // cast
        CSM_CAST_EXPRESSION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
        CSM_FUN_TYPE_CAST_EXPRESSION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

        // function call
        CSM_FUNCALL_EXPRESSION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	// This is just an end marker of the token types, related with expressions
	// Do NOT create tokens of this type
	// Place token types, which correspond to expressions only BEFORE this type
	// (but AFTER CSM_EXPRESSIONS_START)
	CSM_EXPRESSIONS_END<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	//////////  //////////

	CSM_FOR_INIT_STATEMENT<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_LINKAGE_SPECIFICATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_PTR_OPERATOR<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_ARRAY_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_VARIABLE_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_VARIABLE_LIKE_FUNCTION_DECLARATION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_CONDITION<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;
	CSM_BASE_SPECIFIER<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_TEST<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>;

	CSM_END<AST=org.netbeans.modules.cnd.modelimpl.parser.FakeAST>; // dummy token - should be AFTER ALL CSM_...
}

{
    private CppParserAction action;
    protected CPPParser(TokenStream stream, CppParserAction action) {
        this(stream);
        this.action = action;
    }

    // Defines for flags passed to init methods
    public static final int CPP_STATEMENT_TRACE		= 0x1;
    public static final int CPP_STATEMENT_TRACE_VERBOSE = 0x2;
    public static final int CPP_SUPPRESS_ERRORS		= 0x4;

    public static final int CPP_CPLUSPLUS		= 0x8;
    public static final int CPP_ANSI_C			= 0x10;
    public static final int CPP_KandR_C			= 0x20;
    
    public static final int CPP_FLAVOR_CPP11            = 0x40;

    /** Switches legacy warnings on */
    protected static final boolean reportOddWarnings = Boolean.getBoolean("cnd.parser.odd.warnings");

    protected void addNewFold(int type, int startLnum, int startOffset, int endLnum, int endOffset) {}

    //	The statements in this block appear only in CPPParser.cpp and not in CPPLexer.cpp

    public static final
    int statementTrace = 0;	// Used to control selected (level) tracing (see support.cpp)
				// 1 Shows which external and member statements selected
				// 2 Shows above plus all declarations/definitions
				// 3 reserved for future use
				// 4 and above available for user

     protected boolean isLazyCompound() {
        return false;
    }

    protected void init(String filename, int flags) {

	setFilename(filename);
	//
	// Creates a dictionary to hold symbols with 4001 buckets, 200 scopes
	// and 800,000 characters // These can be changed to suit the size of
	// program(s) being parsed.
	//symbols = new CPPDictionary(4001, 200, 800000);

	// Set template parameter and external scopes. Set template parameter scope to 0.
	//templateParameterScope = symbols->getCurrentScopeIndex();
	//symbols->saveScope();	// Advance currentScope from 0 to 1
	//externalScope = symbols->getCurrentScopeIndex();	// Set external scope to 1

	// Declare predefined scope "std" in external scope
	//CPPSymbol *a = new CPPSymbol("std", CPPSymbol::otTypedef);
	//symbols->define("std", a);

	// Global flags to allow for nested declarations
	_td = false;		// For typedef
	_fd = false;		// For friend
	_sc = scInvalid;	// For StorageClass
	_tq = tqInvalid;	// For TypeQualifier
	_ts = tsInvalid;	// For TypeSpecifier
	_ds = dsInvalid;	// For DeclSpecifier

	//functionDefinition = 0;
	qualifierPrefix = new StringBuilder();
	enclosingClass = "";
	assign_stmt_RHS_found = 0;
	in_parameter_list = false;
	K_and_R = false;	// used to distinguish old K & R parameter definitions
	in_return = false;
	is_address = false;
	is_pointer = false;

	/*if ((flags & CPP_STATEMENT_TRACE) > 0) {
	    statementTrace = 1;
	}
	if ((flags & CPP_STATEMENT_TRACE_VERBOSE) > 0) {
	    statementTrace = 2;
	}*/
	if ((flags & CPP_SUPPRESS_ERRORS) > 0) {
	    reportErrors = false;
	}
	if ((flags & CPP_CPLUSPLUS) > 0) {
	    lang = CPLUSPLUS;
	} else if ((flags & CPP_ANSI_C) > 0) {
	    lang = ANSI_C;
	} else if (CPP_KandR_C > 0) { // VK: looks strange; well leave for a while
	    lang = KandR_C;
	} else {
	    lang = UNKNOWN_LANG;
	}

        if ((flags & CPP_FLAVOR_CPP11) > 0) {
            langFlavor = FLAVOR_CPP11;
        } else {
            langFlavor = FLAVOR_UNKNOWN;
        }
    }

    boolean isCPlusPlus() {
	return lang == CPLUSPLUS;
    }

    boolean isCPlusPlus11() {
        return isCPlusPlus() && langFlavor == FLAVOR_CPP11;
    }

    boolean isC() {
        return lang == ANSI_C;
    }

	protected static final int tsInvalid   = 0x0;
	protected static final int tsVOID      = 0x1;
	protected static final int tsCHAR      = 0x2;
	protected static final int tsSHORT     = 0x4;
	protected static final int tsINT       = 0x8;
	protected static final int tsLONG      = 0x10;
	protected static final int tsFLOAT     = 0x20;
	protected static final int tsDOUBLE    = 0x40;
	protected static final int tsSIGNED    = 0x80;
	protected static final int tsUNSIGNED  = 0x100;
	protected static final int tsTYPEID    = 0x200;
	protected static final int tsSTRUCT    = 0x400;
	protected static final int tsENUM      = 0x800;
	protected static final int tsUNION     = 0x1000;
	protected static final int tsCLASS     = 0x2000;
	protected static final int tsWCHAR_T   = 0x4000;
	protected static final int tsBOOL      = 0x8000;
	protected static final int tsCOMPLEX   = 0x10000;
	protected static final int tsIMAGINARY = 0x20000;
        protected static final int tsAUTO      = 0x40000; // c++11 auto type specifier
        protected static final int tsOTHER     = 0x80000;

	public static class TypeQualifier extends Enum { public TypeQualifier(String id) { super(id); } }

	protected static final TypeQualifier tqInvalid = new TypeQualifier("tqInvalid");
	protected static final TypeQualifier tqCONST = new TypeQualifier("tqCONST");
	protected static final TypeQualifier tqVOLATILE = new TypeQualifier("tqVOLATILE");
	protected static final TypeQualifier tqCDECL = new TypeQualifier("tqCDECL");
	protected static final TypeQualifier tqOTHER = new TypeQualifier("tqOTHER");

	public static class StorageClass extends Enum { public StorageClass(String id) { super(id); } }

	protected static final StorageClass scInvalid = new StorageClass("scInvalid");
	protected static final StorageClass scAUTO = new StorageClass("scAUTO");
	protected static final StorageClass scREGISTER = new StorageClass("scREGISTER");
	protected static final StorageClass scSTATIC = new StorageClass("scSTATIC");
	protected static final StorageClass scEXTERN = new StorageClass("scEXTERN");
	protected static final StorageClass scMUTABLE = new StorageClass("scMUTABLE");
	protected static final StorageClass scTHREAD = new StorageClass("scTHREAD");
	protected static final StorageClass scOTHER = new StorageClass("scOTHER");

	public static class DeclSpecifier extends Enum { public DeclSpecifier(String id) { super(id); } }

	protected static final DeclSpecifier dsInvalid = new DeclSpecifier("dsInvalid");
	protected static final DeclSpecifier dsVIRTUAL = new DeclSpecifier("dsVIRTUAL");
	protected static final DeclSpecifier dsINLINE = new DeclSpecifier("dsINLINE");
	protected static final DeclSpecifier dsEXPLICIT = new DeclSpecifier("dsEXPLICIT");
	protected static final DeclSpecifier dsFRIEND = new DeclSpecifier("dsFRIEND");

        protected static final String LITERAL_EXEC = "EXEC";
        protected static final String LITERAL_SQL = "SQL";

	// typedef int QualifiedItem;
	protected static final int qiInvalid     = 0x0;
	protected static final int qiType        = 0x1;	// includes enum, class, typedefs, namespace
	protected static final int qiDtor        = 0x2;
	protected static final int qiCtor        = 0x4;
	protected static final int qiOperator    = 0x8;
	protected static final int qiPtrMember   = 0x10;
	protected static final int qiVar         = 0x20;
	protected static final int qiFun         = 0x40;
	
	// Language Definitions
	// TODO: what's the difference with the above constants (CPP_ANSI_C, etc)
	protected static final  int UNKNOWN_LANG	= 0x0;
	protected static final  int CPLUSPLUS	= 0x2;
	protected static final  int ANSI_C	= 0x4;
	protected static final  int KandR_C	= 0x8;

        // Language Flavors
        protected static final  int FLAVOR_UNKNOWN  = 0x0;
        protected static final  int FLAVOR_CPP11    = 0x1;

        protected static final int ERROR_LIMIT = 100;
	private int errorCount = 0;

    protected static final int declOther = 0;
    protected static final int declStatement = 1;
    protected static final int declGeneric = 2;
    protected static final int declNotFirst = 3;
    protected static final int declFunctionParam = 4;
    protected static final int declExternFunction = 5;
    protected static final int declSimpleFunction = 6;

	public int getErrorCount() {
	    int cnt = errorCount;
	    return cnt;
	}

        public boolean shouldProceed() {
            boolean res = errorCount < ERROR_LIMIT;
            if (!res) {
                reportError("Too many errors. Parsing is being stopped."); // NOI18N
            }
            return res;
        }

	public void reportError(RecognitionException e) {
            // Do not report errors that we had reported already
            if (lastRecoveryPosition == input.index()) {
                return;
            }

            onError(e);
            
            if (Diagnostic.needStatistics()) Diagnostic.onParserError(e);

	    if (reportErrors) {
                if (TraceFlags.DEBUG) {
                    e.printStackTrace(System.err);
                } else {
                    super.reportError(e);
                }
	    }
	    errorCount++;
	}

	public void reportError(String s) {
	    if (reportErrors) {
		super.reportError(s);
	    }
	    errorCount++;
	}

        // Set of tokens stopping recovery
        private static final BitSet stopSet = new BitSet();
        static {
            stopSet.add(LCURLY);
            stopSet.add(RCURLY);
            stopSet.add(RPAREN);
            stopSet.add(LPAREN);
            //stopSet.add(LSQUARE);
            //stopSet.add(RSQUARE);
        }
        
        private static final int RECOVERY_LIMIT = 20;
        private int recoveryCounter = 0;
        private int lastRecoveryPosition = -1;
        
        public void recover(RecognitionException ex, BitSet tokenSet) {
            if (lastRecoveryPosition == input.index()) {
                if (recoveryCounter > RECOVERY_LIMIT) {
                    consume();
                    recoveryCounter = 0;
                } else {
                    recoveryCounter++;
                }
            } else {
                recoveryCounter = 0;
                lastRecoveryPosition = input.index();
            }
            tokenSet.orInPlace(stopSet);
            consumeUntil(tokenSet);
	}

        public boolean isTemplateTooDeep(int currentLevel, int maxLevel) {
            return isTemplateTooDeep(currentLevel, maxLevel, 0);
        }
	
        public static int TEMPLATE_PREVIEW_POS_LIMIT = 4096;
        public boolean isTemplateTooDeep(int currentLevel, int maxLevel, int startPos) {
            int level = currentLevel;
            int pos = startPos;            
            while(pos < TEMPLATE_PREVIEW_POS_LIMIT) {
                int token = LA(pos);
                pos++;
                if(token == EOF || token == 0) {
                    break;
                }
                if(token == LCURLY || token == RCURLY) {
                    break;
                }
                if(token == LESSTHAN) {
                    level++;
                } else if(token == GREATERTHAN) {
                    level--;
                } 
                if(level == 0) {
                    return false;
                }
                if(level >= maxLevel) {
                    return true;
                }
            }
            return false;
        }


	//protected boolean isCtor() { /*TODO: implement*/ throw new NotImplementedException(); }
	//protected boolean isValidIdentifier(String id) { /*TODO: implement*/ throw new NotImplementedException(); }

	protected
	int lang;

	protected
	int langFlavor;

	// Symbol table management stuff
	//CPPDictionary *symbols;

	//protected
	//int templateParameterScope;

	//protected
	//int externalScope;

	protected
	boolean _td;			// For typedef

	protected
	boolean _fd;			// For friend

	protected
	StorageClass _sc;	// For storage class

	protected
	TypeQualifier _tq;	// For type qualifier

	protected
	/*TypeSpecifier*/int _ts;	// For type specifier

	protected
	DeclSpecifier _ds;	// For declaration specifier

	/*protected
	int functionDefinition;	// 0 = Function definition not being parsed
				// 1 = Parsing function name
				// 2 = Parsing function parameter list
				// 3 = Parsing function block*/

	protected
	StringBuilder qualifierPrefix = new StringBuilder();

	protected
	String enclosingClass;

	int assign_stmt_RHS_found;

	boolean in_parameter_list;	// DW 13/02/04 used within CPP_parser
	boolean K_and_R;	// used to distinguish old K & R parameter definitions
	boolean in_return;
	boolean is_address;
	boolean is_pointer;

        private static final int NESTED_CLASSES_LIMIT = 32;

        protected int classDefinitionDepth = 0; // to restrict number of nested classes

	protected int MaxTemplateTokenScan = 200;

	static class IF_Type extends Enum { public IF_Type(String id) { super(id); } }
	protected static final IF_Type IF_Local = new IF_Type("IF_Local");
	protected static final IF_Type IF_System = new IF_Type("IF_System");
	protected static final IF_Type IF_Macro = new IF_Type("IF_Macro");

	static class IncludeFile {
	    public IF_Type type;
	    public String file;
	}

	// Semantic interface; You could subclass and redefine these functions
	//  so you don't have to mess with the grammar itself.

	// Antlr doesn't allow to make parser abstract;
	// I throw this exception in methods, which otherwise were just abstract 
	public static class NotImplementedException extends Error {
		public NotImplementedException() { super("not imlemented"); }
	}
	
	// Symbol stuff
	protected boolean qualifiedItemIsOneOf(/*QualifiedItem*/int qiFlags) { return qualifiedItemIsOneOf(qiFlags, 0); }
	protected boolean qualifiedItemIsOneOf(/*QualifiedItem*/int qiFlags, int lookahead_offset) { /*TODO: implement*/ throw new NotImplementedException(); }

	protected /*QualifiedItem*/int qualifiedItemIs()	{ return qualifiedItemIs(0); }
	protected /*QualifiedItem*/int qualifiedItemIs(int lookahead_offset) { /*TODO: implement*/ throw new NotImplementedException(); }

	// both skipTemplateQualifiers and skipNestedParens used only in CPPParserEx
	//protected boolean skipTemplateQualifiers(int kInOut) { /*TODO: implement*/ throw new NotImplementedException(); }
	// TODO: original skipNestedParens(int& kInOut) passes kInOut BY REF!
	//protected int skipNestedParens(int kInOut) { /*TODO: implement*/ throw new NotImplementedException(); }

	protected boolean scopedItem() { return scopedItem(1); }
	protected boolean scopedItem(int k) { /*TODO: implement*/ throw new NotImplementedException(); }

	// finalQualifier is used in CPPParserEx only
	//protected int finalQualifier() { return finalQualifier(1); }
	//protected int finalQualifier(final int k) { /*TODO: implement*/ throw new NotImplementedException(); }

	protected boolean isTypeName(CharSequence s) { /*TODO: implement*/ throw new NotImplementedException(); }
        protected CharSequence getTokenText(Token token) { /*TODO: implement*/ throw new NotImplementedException(); }
	// isClassName is used in CPPParserEx only
	//protected boolean isClassName(String  s) { /*TODO: implement*/ throw new NotImplementedException(); }
	//protected void end_of_stmt() {}


	// Scoping stuff
	//protected void enterNewLocalScope() {}
	//protected void exitLocalScope() {}
	//protected void enterExternalScope() {}
	//protected void exitExternalScope() {}

	// Aggregate stuff
	protected void classForwardDeclaration(/*TypeSpecifier*/int ts, DeclSpecifier ds, String tag) {}

	protected void beginClassDefinition(/*TypeSpecifier*/int ts, String tag) {
            classDefinitionDepth++;
        }

	protected void endClassDefinition() {
            classDefinitionDepth--;
        }
        
        protected boolean checkClassDefinitionDepth(int maxDepth) {
            return classDefinitionDepth < maxDepth;
        }

	protected void beginEnumDefinition(String s) {}
	protected void endEnumDefinition() {}
	protected void enumElement(String s) {}

	// Declaration and definition stuff
	protected void declarationSpecifier(boolean td, boolean fd, StorageClass sc, TypeQualifier tq,
			     /*TypeSpecifier*/int ts, DeclSpecifier ds) {}
	protected void beginDeclaration() {}
	protected void endDeclaration() {}
	protected void beginConstructorDeclaration(String s) {}
	protected void endConstructorDeclaration() {}
	protected void beginDestructorDeclaration(String s) {}
	protected void endDestructorDeclaration() {}
	protected void beginParameterDeclaration() {}
	protected void beginFieldDeclaration() {}
	//protected void beginFunctionDefinition() {}
	//protected void endFunctionDefinition() {}
	//protected void functionParameterList() {}
	//protected void functionEndParameterList(boolean def) {}
	//protected void beginConstructorDefinition() {}
	//protected void endConstructorDefinition() {}
	//protected void beginDestructorDefinition() {}
	//protected void endDestructorDefinition() {}

	// Declarator stuff
	protected void declaratorID(String s, /*QualifiedItem*/int qi) {}	// stores new symbol with type
	protected void declaratorArray() {}
	//protected void declaratorParameterList(boolean def) {}
	//protected void declaratorEndParameterList(boolean def) {}

	// template stuff
	protected void templateTypeParameter(String s) {}
	//protected void beginTemplateDeclaration() {}
	//protected void endTemplateDeclaration() {}
	protected void beginTemplateDefinition() {}
	protected void endTemplateDefinition() {}
	//protected void beginTemplateParameterList() {}
	//protected void endTemplateParameterList() {}

	// exception stuff
	//protected void exceptionBeginHandler() {}
	//protected void exceptionEndHandler() {}
	protected void panic(String s) {}

	boolean reportErrors = true;

	// myCode functions ready for overriding in MyCode subclass

	//protected int getOffset() { /*TODO: implement*/ throw new NotImplementedException(); }
	//protected int getLine()	{ /*TODO: implement*/ throw new NotImplementedException(); }

	protected void printf(String pattern, Object... params) { /*TODO: implement*/ throw new NotImplementedException(); }

	protected boolean balanceBraces(int left, int right) { throw new NotImplementedException(); };

        protected boolean checkTemplateExplicitSpecialization() { throw new NotImplementedException(); }

        /** Is called when an error occurred */
        protected void onError(RecognitionException e) {}
}

public translation_unit:
		//{enterExternalScope();}
                /* Do not generate ambiguity warnings: we intentionally want to match everything that
                   can not be matched in external_declaration in the second alternative */
		(options{generateAmbigWarnings = false;}:
            { LT(1).getText().equals(LITERAL_EXEC) && LT(2).getText().equals(LITERAL_SQL) }? (literal_ident literal_ident) => pro_c_statement
        |
            {shouldProceed() && !isCPlusPlus11()}? (LSQUARE) =>
            /* This alternative fixes recovery problem happened because C++11 declaration
               could begin with LSQAURE token (see c++11 attributes). This
               breaks recovery for C++98 because rule external_declaration now
               will be called when declaration starts with LSQUARE, so the last
               alternative for recovering will not work. It seems that better solution is
               to track that function 'recover' was called (that means an error occured) but
               input.index() was not changed. In that case it is normal to consume one token
               like in the last alternative.
            */ 
            .! { reportError(new NoViableAltException(LT(0), getFilename())); }
        |
            {shouldProceed()}?
            external_declaration             
        |
            {shouldProceed()}?
            /* Here we match everything that can not be matched by external_declaration rule,
               report it as an error and not include in AST */
            .! { reportError(new NoViableAltException(LT(0), getFilename())); }
        )* EOF!
		{/*exitExternalScope();*/ #translation_unit = #(#[CSM_TRANSLATION_UNIT, getFilename()], #translation_unit);}
       ;

//
// it's a caller's responsibility to check isCPlusPlus
//
protected
template_explicit_specialization
{String s; TypeQualifier tq; StorageClass sc;int ts = 0; boolean b;}
    :
    LITERAL_template LESSTHAN GREATERTHAN
    (
        // Template explicit specialisation function definition (VK 30/05/06)
        ((LITERAL_template LESSTHAN GREATERTHAN)? declaration_specifiers[false, false] function_declarator[true, false, false] (LCURLY | literal_try | ASSIGNEQUAL (LITERAL_default | LITERAL_delete)))=>
        (LITERAL_template LESSTHAN GREATERTHAN)?
        {if(statementTrace >= 1) printf("external_declaration_0a[%d]: template " + "explicit-specialisation function definition\n", LT(1).getLine());}
        function_definition
        { #template_explicit_specialization = #(#[CSM_TEMPLATE_FUNCTION_DEFINITION_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_FUNCTION_DEFINITION_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
    |
        // Template explicit specialisation ctor definition
        (   ctor_decl_spec ctor_declarator[true]
            ( COLON         // DEFINITION :ctor_initializer
            | LCURLY        // DEFINITION (compound Statement) ?
            | ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
            )
        ) =>
        {if(statementTrace >= 1) printf("template_explicit_specialization_0b[%d]: template " + "explicit-specialisation ctor definition\n", LT(1).getLine());}
        ctor_definition
        { #template_explicit_specialization = #(#[CSM_TEMPLATE_CTOR_DEFINITION_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_CTOR_DEFINITION_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
    |
	// Template explicit specialisation dtor definition
		(dtor_declarator[true] LCURLY)=>
		{if(statementTrace >= 1)
			printf("template_explicit_specialization_0b[%d]: template " +
				"explicit-specialisation dtor definition\n", LT(1).getLine());
		}
		dtor_definition
		//{ #template_explicit_specialization = #(#[CSM_TEMPLATE_FUNCTION_DEFINITION_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_FUNCTION_DEFINITION_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
        { #template_explicit_specialization = #(#[CSM_TEMPLATE_DTOR_DEFINITION_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_DTOR_DEFINITION_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
	| 
        // Template explicit specialisation ctor declaration 
		(ctor_declarator[false] SEMICOLON)=>
		{if(statementTrace >= 1)
			printf("template_explicit_specialization_0c[%d]: template " +
				"explicit-specialisation ctor declaration\n", LT(1).getLine());
		}
		b = ctor_declarator[false] SEMICOLON
		{ #template_explicit_specialization = #(#[CSM_TEMPLATE_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
        // Template explicit specialisation dtor declaration        
        |
		(dtor_declarator[false] SEMICOLON)=>
		{if(statementTrace >= 1)
			printf("template_explicit_specialization_0d[%d]: template " +
				"explicit-specialisation dtor definition\n", LT(1).getLine());
		}
		dtor_declarator[false] SEMICOLON
		{ #template_explicit_specialization = #(#[CSM_TEMPLATE_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }

        |
        // Template explicit specialisation dtor declaration
		(class_forward_declaration)=>
		{if(statementTrace >= 1)
			printf("template_explicit_specialization_0f[%d]: template " +
				"class forward explicit-specialisation\n", LT(1).getLine());
		}
		declaration_specifiers[false, false] SEMICOLON
		{ #template_explicit_specialization = #(#[CSM_FWD_TEMPLATE_EXPLICIT_SPECIALIZATION, "CSM_FWD_TEMPLATE_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
        |
            (   (LITERAL___extension__!)?
                (LITERAL_template LESSTHAN GREATERTHAN)?
                (   storage_class_specifier
                |   cv_qualifier
                |   LITERAL_typedef
                )*
                enum_def_head
            ) =>
            (LITERAL___extension__!)?
            (LITERAL_template LESSTHAN GREATERTHAN)?
                (   sc = storage_class_specifier
                |   tq = cv_qualifier
                |   LITERAL_typedef
            )*
            enum_specifier (init_declarator_list[declOther])? 
            SEMICOLON
            { #template_explicit_specialization = #(#[CSM_ENUM_DECLARATION, "CSM_ENUM_DECLARATION"], #template_explicit_specialization); }
        |
            (   (LITERAL___extension__!)?
                (LITERAL_template LESSTHAN GREATERTHAN)?
                (   storage_class_specifier
                |   cv_qualifier
                |   LITERAL_typedef
                )*
                LITERAL_enum (LITERAL_class | LITERAL_struct)? (qualified_id)? (COLON ts = type_specifier[dsInvalid, false])? SEMICOLON
            ) =>
            (LITERAL___extension__!)?
            (LITERAL_template LESSTHAN GREATERTHAN)?
                (   sc = storage_class_specifier
                |   tq = cv_qualifier
                |   LITERAL_typedef
            )*
            enum_specifier
            SEMICOLON
            { #template_explicit_specialization = #(#[CSM_ENUM_FWD_DECLARATION, "CSM_ENUM_FWD_DECLARATION"], #template_explicit_specialization); }
        |
        // Template explicit specialisation for type cast operator
            (   (LITERAL___extension__!)?
                (LITERAL_template LESSTHAN GREATERTHAN)?
                (   literal_inline
                |   cv_qualifier
                |   LITERAL_constexpr
                )*
                scope_override LITERAL_OPERATOR
            ) =>
            (   (LITERAL___extension__!)?
                (LITERAL_template LESSTHAN GREATERTHAN)?
                (   literal_inline
                |   tq = cv_qualifier
                |   LITERAL_constexpr
                )*
                s = scope_override b = conversion_function_decl_or_def 
            )
            { if (b) #template_explicit_specialization = #(#[CSM_USER_TYPE_CAST_DEFINITION_EXPLICIT_SPECIALIZATION, "CSM_USER_TYPE_CAST_DEFINITION_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization);
              else #template_explicit_specialization = #(#[CSM_TEMPLATE_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
        |
	// Template explicit specialisation (DW 14/04/03)
		{if(statementTrace >= 1)
			printf("template_explicit_specialization_0e[%d]: template " +
				"explicit-specialisation\n", LT(1).getLine());
		}
        (LITERAL_template LESSTHAN GREATERTHAN)?
		declaration[declOther]
		{ #template_explicit_specialization = #(#[CSM_TEMPLATE_EXPLICIT_SPECIALIZATION, "CSM_TEMPLATE_EXPLICIT_SPECIALIZATION"], #template_explicit_specialization); }
	)
	;

//
// it's a caller's responsibility to check isCPlusPlus
//
protected
external_declaration_template { String s; K_and_R = false; boolean ctrName=false; boolean definition; boolean friend = false; TypeQualifier tq; StorageClass sc;int ts = 0;}
    :
        ((LITERAL___extension__)? LITERAL_template LESSTHAN GREATERTHAN) => 
        (
            (LITERAL___extension__!)?
            (
                {checkTemplateExplicitSpecialization()}? 
                template_explicit_specialization
            |
                declaration_template_impl
            )
        )
    |
        (LITERAL_template (LITERAL_class | LITERAL_struct| LITERAL_union)) =>
        LITERAL_template (LITERAL_class | LITERAL_struct| LITERAL_union) 
        s=scope_override s=literal_ident (LESSTHAN template_argument_list GREATERTHAN)? SEMICOLON
        {#external_declaration_template = #(#[CSM_TEMPLATE_EXPLICIT_INSTANTIATION, "CSM_TEMPLATE_EXPLICIT_INSTANTIATION"], #external_declaration_template);}
    |
        (LITERAL_template (~LESSTHAN)) =>
        LITERAL_template
        (
            (scope_override LITERAL_OPERATOR)=>
                s=scope_override conversion_function_decl
        |
            declaration[declOther]
        )
        {#external_declaration_template = #(#[CSM_TEMPLATE_EXPLICIT_INSTANTIATION, "CSM_TEMPLATE_EXPLICIT_INSTANTIATION"], #external_declaration_template);}	
    |
        declaration_template_impl
    ;

protected
declaration_template_impl { String s; K_and_R = false; boolean ctrName=false; boolean definition; boolean friend = false; TypeQualifier tq; StorageClass sc;int ts = 0;}
    :
        {beginTemplateDefinition();}
        (
            options {greedy=true;} :
            (
                (LITERAL_template LESSTHAN GREATERTHAN) => 
                    LITERAL_template LESSTHAN! GREATERTHAN! // just swallow tokens
                |
                    template_head
            )
        )+
		(   
                // Class template definition
                (class_head)=>
                {if (statementTrace>=1) 
                    printf("declaration_template_impl_1b[%d]: Class template definition\n",
                        LT(1).getLine());
                }
                declaration[declOther]
                { #declaration_template_impl = #(#[CSM_TEMPLATE_CLASS_DECLARATION, "CSM_TEMPLATE_CLASS_DECLARATION"], #declaration_template_impl); }
            |
                // Templated FUNCTIONS and CONSTRUCTORS matched here.
                // Templated CONSTRUCTOR declaration
                (	
                        ctor_decl_spec
                        /*{qualifiedItemIsOneOf(qiCtor)}?*/
                        ctor_declarator[false] (EOF|SEMICOLON)
                )=>
                {if (statementTrace>=1) 
                        printf("declaration_template_impl_11a[%d]: Constructor or no-ret type fun declarator\n",
                                LT(1).getLine());
                }
                friend = ctor_decl_spec
//                {ctrName = qualifiedItemIsOneOf(qiCtor);}
                ctrName = ctor_declarator[false]
                (
                        EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
                    |   
                        SEMICOLON  // Constructor declarator
                )
                {
                    // below is a workaround for know infinite loop bug in ANTLR 
                    // see http://www.jguru.com/faq/view.jsp?EID=271922
                    //if( #cds1 != null ) { #cds1.setNextSibling(null); }; 
                    if (ctrName && !friend) {
                        #declaration_template_impl= #(#[CSM_CTOR_TEMPLATE_DECLARATION, "CSM_CTOR_TEMPLATE_DECLARATION"],  #declaration_template_impl); //end_of_stmt();
                    } else {
                        #declaration_template_impl= #(#[CSM_FUNCTION_TEMPLATE_DECLARATION, "CSM_FUNCTION_TEMPLATE_DECLARATION"],  #declaration_template_impl); //end_of_stmt();
                    }
                }

            |   
                // Templated CONSTRUCTOR definition
                // JEL 4/3/96.. Added predicate that works once the
                // restriction is added that ctor cannot be virtual
                (  
                    ctor_decl_spec                            
                    /*{qualifiedItemIsOneOf(qiCtor)}?*/
                    ctor_declarator[true]
                )=>
                {if (statementTrace>=1) 
                    printf("declaration_template_impl_11b[%d]: Template constructor " +
                        "definition\n", LT(1).getLine());
                }
                // TODO: use ctor_definition here
                friend = ctor_decl_spec
                ctrName = ctor_declarator[true]
                (ctor_body | ASSIGNEQUAL (LITERAL_default | LITERAL_delete))
                {
                    if (ctrName && !friend) {
                        #declaration_template_impl= #(#[CSM_CTOR_TEMPLATE_DEFINITION, "CSM_CTOR_TEMPLATE_DEFINITION"],  #declaration_template_impl); //end_of_stmt();
                    } else {
                        #declaration_template_impl= #(#[CSM_FUNCTION_TEMPLATE_DEFINITION, "CSM_FUNCTION_TEMPLATE_DEFINITION"],  #declaration_template_impl); //end_of_stmt();
                    }
                }
            |  
                // User-defined type cast
                {isCPlusPlus()}?
                ((literal_inline | LITERAL_constexpr)? scope_override conversion_function_decl_or_def)=>
                {if (statementTrace>=1) 
                        printf("external_declaration_6[%d]: Operator function\n",
                                LT(1).getLine());
                }
                (literal_inline | LITERAL_constexpr)? s = scope_override definition = conversion_function_decl_or_def 
                { if( definition ) #declaration_template_impl = #(#[CSM_USER_TYPE_CAST_TEMPLATE_DEFINITION, "CSM_USER_TYPE_CAST_TEMPLATE_DEFINITION"], #declaration_template_impl);
                    else	   #declaration_template_impl = #(#[CSM_USER_TYPE_CAST_TEMPLATE_DECLARATION, "CSM_USER_TYPE_CAST_TEMPLATE_DECLARATION"], #declaration_template_impl); }
            |
                // Templated function declaration
                (declaration_specifiers[false, false] function_declarator[false, false, false] SEMICOLON)=> 
                {if (statementTrace>=1) 
                    printf("declaration_template_impl_11c[%d]: Function template " +
                        "declaration\n", LT(1).getLine());
                }
                declaration[declOther]
                { #declaration_template_impl = #(#[CSM_FUNCTION_TEMPLATE_DECLARATION, "CSM_FUNCTION_TEMPLATE_DECLARATION"], #declaration_template_impl); }
            |
                // Templated function definition
                (declaration_specifiers[false, false] function_declarator[true, false, false] (LCURLY | literal_try | ASSIGNEQUAL (LITERAL_default | LITERAL_delete)))=>
                {if (statementTrace>=1) printf("declaration_template_impl_11d[%d]: Function template " + "definition\n", LT(1).getLine());}
                function_definition
                { #declaration_template_impl = #(#[CSM_FUNCTION_TEMPLATE_DEFINITION, "CSM_FUNCTION_TEMPLATE_DEFINITION"], #declaration_template_impl); }
            |
                // Destructor DEFINITION (templated)
                (   dtor_head[true] 
                    (   LCURLY
                    |   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
                    )
                )=>
                    {if (statementTrace>=1) 
                        printf("external_declaration_4[%d]: Destructor definition\n",
                            LT(1).getLine());
                    }
                    dtor_head[true] 
                    (   
                        dtor_body
                    |   
                        ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
                    )
                    { #declaration_template_impl = #(#[CSM_DTOR_TEMPLATE_DEFINITION, "CSM_DTOR_TEMPLATE_DEFINITION"], #declaration_template_impl); }
            |
                (LITERAL_using literal_ident ASSIGNEQUAL) => alias_declaration
                { #declaration_template_impl = #(#[CSM_GENERIC_DECLARATION, "CSM_GENERIC_DECLARATION"], #declaration_template_impl); }
            |
                (   (LITERAL___extension__!)?
                    (   storage_class_specifier
                    |   cv_qualifier
                    |   LITERAL_typedef
                    )*
                    enum_def_head
                ) =>
                (LITERAL___extension__!)?
                    (   sc = storage_class_specifier
                    |   tq = cv_qualifier
                    |   LITERAL_typedef
                )*
                enum_specifier (init_declarator_list[declOther])? 
                SEMICOLON
                { #declaration_template_impl = #(#[CSM_ENUM_DECLARATION, "CSM_ENUM_DECLARATION"], #declaration_template_impl); }
            |
                (   (LITERAL___extension__!)?
                    (   storage_class_specifier
                    |   cv_qualifier
                    |   LITERAL_typedef
                    )*
                    LITERAL_enum (LITERAL_class | LITERAL_struct)? (qualified_id)? (COLON ts = type_specifier[dsInvalid, false])? SEMICOLON
                ) =>
                (LITERAL___extension__!)?
                    (   sc = storage_class_specifier
                        |   tq = cv_qualifier
                        |   LITERAL_typedef
                    )*
                enum_specifier
                SEMICOLON
                { #declaration_template_impl = #(#[CSM_ENUM_FWD_DECLARATION, "CSM_ENUM_FWD_DECLARATION"], #declaration_template_impl); }
            |  
                // templated forward class decl, init/decl of static member in template
                            // Changed alternative order as a fix for IZ#138099:
                            // unresolved identifier for functions' template parameter.
                            // If this alternative is before function declaration
                            // then code like "template<T> int foo(T);" incorrectly
                            // becomes a CSM_TEMPL_FWD_CL_OR_STAT_MEM.

                (declaration_specifiers[true, false]
                    (init_declarator_list[declOther])? SEMICOLON /*{end_of_stmt();}*/)=>
                //{beginTemplateDeclaration();}
                { if (statementTrace>=1) 
                    printf("declaration_template_impl_10[%d]: Class template declaration\n",
                        LT(1).getLine());
                }
                declaration_specifiers[true, false]
                    (init_declarator_list[declOther])? SEMICOLON //{end_of_stmt();}
                {/*endTemplateDeclaration();*/ #declaration_template_impl = #(#[CSM_TEMPL_FWD_CL_OR_STAT_MEM, "CSM_TEMPL_FWD_CL_OR_STAT_MEM"], #declaration_template_impl);}
        )
        {endTemplateDefinition();}
    ;

protected 
typedef_enum
        :
                {if(statementTrace>=1) 
                        printf("typedef_enum [%d]\n",LT(1).getLine());
                }                     
                LITERAL_typedef 
                {declarationSpecifier(true, false, scInvalid, tqInvalid, tsInvalid, dsInvalid);} 
                enum_specifier 
                (init_declarator_list[declOther])? SEMICOLON //{end_of_stmt();}
        ;

external_declaration {String s; K_and_R = false; boolean definition;StorageClass sc;TypeQualifier tq; int ts = 0;}
	:  
	(
                {isCPlusPlus()}?
		// Suppressed instantiation of the following declaration
		{if (statementTrace>=1) 
			printf("external_declaration_0[%d]: Suppressed instantiation of the following declaration\n",
				LT(1).getLine());
		}
                ((LITERAL___extension__)? LITERAL_extern LITERAL_template)=>
		(LITERAL___extension__!)? LITERAL_extern LITERAL_template external_declaration
		{ #external_declaration = #(#[CSM_EXTERN_TEMPLATE, "CSM_EXTERN_TEMPLATE"], #external_declaration); }
        |
	    {isCPlusPlus()}? ((LITERAL___extension__)? (LITERAL_export)? LITERAL_template) => external_declaration_template
        |
	// Class definition (templates too)
	// This is separated out otherwise the next alternative
	// would look for "class A { ... } f() {...}" which is
	// an unacceptable level of backtracking.

	// JEL Note:  Rule body does not need typedef, because
	// that is internal to "declaration", and it is invalid
	// to say "typedef template..."
	 	// Class definition
                // we need "static" here for the case "static struct XX {...} myVar; - see issue #106652

//		((LITERAL_typedef | LITERAL_static)? class_head)=>
        ((LITERAL___extension__!)? (decl_specifiers_before_type)? class_head) =>
        {action.simple_declaration(LT(1));}
        {action.class_declaration(LT(1));}
		(LITERAL___extension__!)? declaration[declOther]
		{ #external_declaration = #(#[CSM_CLASS_DECLARATION, "CSM_CLASS_DECLARATION"], #external_declaration); }
    |
        // Enum definition (don't want to backtrack over this in other alts)
        ((LITERAL___extension__!)? (decl_specifiers_before_type)? enum_def_head) =>
        {action.simple_declaration(LT(1));}
        {action.enum_declaration(LT(1));}
        {if (statementTrace>=1) printf("external_declaration_3[%d]: Enum definition\n",LT(1).getLine());}
        (LITERAL___extension__!)? declaration[declOther]
        {action.end_enum_declaration(LT(1));}
        {action.end_simple_declaration(LT(1));}
        { #external_declaration = #(#[CSM_ENUM_DECLARATION, "CSM_ENUM_DECLARATION"], #external_declaration); }
    |
        // Enum forward declaration (don't want to backtrack over this in other alts)
        ((LITERAL___extension__!)? (decl_specifiers_before_type)? enum_fwd_head) =>
        {action.simple_declaration(LT(1));}
        {action.enum_declaration(LT(1));}
        {if (statementTrace>=1) printf("external_declaration_3[%d]: Enum definition\n",LT(1).getLine());}
        (LITERAL___extension__!)? declaration[declOther]
        {action.end_enum_declaration(LT(1));}
        {action.end_simple_declaration(LT(1));}
        { #external_declaration = #(#[CSM_ENUM_FWD_DECLARATION, "CSM_ENUM_FWD_DECLARATION"], #external_declaration); }
    |
		// Destructor DEFINITION (templated or non-templated)
		{isCPlusPlus()}?
		(   (template_head)? 
                    dtor_head[true] 
                    (   LCURLY
                    |   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
                    )
                )=>
		{if (statementTrace>=1) 
			printf("external_declaration_4[%d]: Destructor definition\n",
				LT(1).getLine());
		}
		(template_head)? 
                dtor_head[true]
                (   dtor_body
                |   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
                )
		{ #external_declaration = #(#[CSM_DTOR_DEFINITION, "CSM_DTOR_DEFINITION"], #external_declaration); }
	|
		// Constructor DEFINITION (non-templated)
		{isCPlusPlus()}?
		(	(options {warnWhenFollowAmbig = false;}: ctor_decl_spec)?
			{qualifiedItemIsOneOf(qiCtor)}?
		)=>
		{if (statementTrace>=1) 
			printf("external_declaration_5[%d]: Constructor definition\n",
				LT(1).getLine());
		}
		ctor_definition
		{ #external_declaration = #(#[CSM_CTOR_DEFINITION, "CSM_CTOR_DEFINITION"], #external_declaration); }
	|  
		// User-defined type cast
		{isCPlusPlus()}?
		((template_head)? (literal_inline | LITERAL_constexpr)? scope_override conversion_function_decl_or_def)=>
		{if (statementTrace>=1) 
			printf("external_declaration_6[%d]: Operator function\n",
				LT(1).getLine());
		}
		(template_head)? (literal_inline | LITERAL_constexpr)? s = scope_override definition = conversion_function_decl_or_def 
		{ if( definition ) #external_declaration = #(#[CSM_USER_TYPE_CAST_DEFINITION, "CSM_USER_TYPE_CAST_DEFINITION"], #external_declaration);
		    else	   #external_declaration = #(#[CSM_USER_TYPE_CAST_DECLARATION, "CSM_USER_TYPE_CAST_DECLARATION"], #external_declaration); }
    |
        // Function declaration
        (   (LITERAL___extension__)?
            (options {greedy=true;} :function_attribute_specification)?
            declaration_specifiers[false, false]
            (options {greedy=true;} :function_attribute_specification)?
            function_declarator[false, false, true] (EOF|SEMICOLON)
        ) =>
        {if (statementTrace>=1) printf("external_declaration_7[%d]: Function prototype\n", LT(1).getLine());}
        (LITERAL___extension__!)? (options {greedy=true;} :function_attribute_specification!)? declaration[declOther]
        { #external_declaration = #(#[CSM_FUNCTION_DECLARATION, "CSM_FUNCTION_DECLARATION"], #external_declaration); }
    |
        // Function declaration
        (   (LITERAL___extension__)?
            (options {greedy=true;} :function_attribute_specification)?
            declaration_specifiers[false, false]
            (options {greedy=true;} :function_attribute_specification)?
            function_declarator[false, false, false] (EOF|SEMICOLON)
        ) =>
        {if (statementTrace>=1) printf("external_declaration_7[%d]: Function prototype\n", LT(1).getLine());}
        (LITERAL___extension__!)? (options {greedy=true;} :function_attribute_specification!)? declaration[declOther]
        { #external_declaration = #(#[CSM_FUNCTION_LIKE_VARIABLE_DECLARATION, "CSM_FUNCTION_LIKE_VARIABLE_DECLARATION"], #external_declaration); }
    |
        // Function declaration without literal_ident in return type
        // IZ 146150 : 'unexpected token: ;' message appears on 'extern int errno;' line
        (   (LITERAL___extension__)?
            (options {greedy=true;} :function_attribute_specification)?
            declaration_specifiers[false, true]
            (options {greedy=true;} :function_attribute_specification)?
            function_declarator[false, true, false] (EOF|SEMICOLON)
        ) =>
        {if (statementTrace>=1) printf("external_declaration_7[%d]: Function prototype\n", LT(1).getLine());}
        (LITERAL___extension__!)? (options {greedy=true;} :function_attribute_specification!)? declaration[declOther]
        { #external_declaration = #(#[CSM_FUNCTION_LIKE_VARIABLE_DECLARATION, "CSM_FUNCTION_LIKE_VARIABLE_DECLARATION"], #external_declaration); }
    |
        // Extern function declaration without return type but with parameters list
        (   (LITERAL___extension__)?
            (options {greedy=true;} :function_attribute_specification)?
            LITERAL_extern
            (options {greedy=true;} :function_attribute_specification)?
            function_declarator[false, false, false] (EOF|SEMICOLON)
        ) =>
        {if (statementTrace>=1) printf("external_declaration_7[%d]: Function prototype\n", LT(1).getLine());}
        (LITERAL___extension__!)? (options {greedy=true;} :function_attribute_specification!)? declaration[declExternFunction]
        { #external_declaration = #(#[CSM_FUNCTION_LIKE_VARIABLE_DECLARATION, "CSM_FUNCTION_LIKE_VARIABLE_DECLARATION"], #external_declaration); }
    |
        // Simple function declaration without return type
        (literal_ident LPAREN (simple_parameter_list)? RPAREN (EOF|SEMICOLON)
        ) =>
        {if (statementTrace>=1) printf("external_declaration_7[%d]: Function prototype\n", LT(1).getLine());}
        (LITERAL___extension__!)? (options {greedy=true;} :function_attribute_specification!)? declaration[declSimpleFunction]
        { #external_declaration = #(#[CSM_FUNCTION_LIKE_VARIABLE_DECLARATION, "CSM_FUNCTION_LIKE_VARIABLE_DECLARATION"], #external_declaration); }
    |
        // Function definition with return value
        (   (LITERAL___extension__)?
            (options {greedy=true;} :function_attribute_specification!)?
            declaration_specifiers[false, false]
            (options {greedy=true;} :function_attribute_specification!)? 
            function_declarator[true, false, false] (LCURLY | literal_try | ASSIGNEQUAL (LITERAL_default | LITERAL_delete))
        ) =>
        {if (statementTrace>=1) printf("external_declaration_8[%d]: Function definition\n", LT(1).getLine());}
        (LITERAL___extension__!)? (options {greedy=true;} :function_attribute_specification!)? function_definition
        { #external_declaration = #(#[CSM_FUNCTION_DEFINITION, "CSM_FUNCTION_DEFINITION"], #external_declaration); }
    |
        // FIXUP: Function definition without return value
        // till not correct hanlding in function_definition (external_declaration_7)
        // functions without return type
		(function_declarator[true, false, false] (function_K_R_parameter_list)? LCURLY)=>
		{if (statementTrace>=1) 
			printf("external_declaration_8a[%d]: Function definition without ret value\n",
				LT(1).getLine());
		}
		function_definition_no_ret_type
		{ #external_declaration = #(#[CSM_FUNCTION_DEFINITION, "CSM_FUNCTION_DEFINITION"], #external_declaration); }
	|
		// K & R Function definition
		(declaration_specifiers[false, false]	function_declarator[true, false, false] declaration[declOther])=>
		{K_and_R = true;
		 if (statementTrace>=1) 
			printf("external_declaration_9[%d]: K & R function definition\n",
				LT(1).getLine());
		}
		function_definition
		{ #external_declaration = #(#[CSM_FUNCTION_DEFINITION, "CSM_FUNCTION_DEFINITION"], #external_declaration); }
        |       // function declaration with function as return type
		((LITERAL___extension__)? declaration_specifiers[false, false] function_declarator_with_fun_as_ret_type[false] (EOF|SEMICOLON))=> 
		{if (statementTrace>=1) 
			printf("external_declaration_7a[%d]: Function prototype with function as return type\n",
				LT(1).getLine());
		}
		function_declaration_with_fun_as_ret_type
		{ #external_declaration = #(#[CSM_FUNCTION_RET_FUN_DECLARATION, "CSM_FUNCTION_RET_FUN_DECLARATION"], #external_declaration); }
                
        |       // function definition with function as return type
                ((LITERAL___extension__)? declaration_specifiers[false, false] function_declarator_with_fun_as_ret_type[true] LCURLY)=> 
		{if (statementTrace>=1) 
			printf("external_declaration_8b[%d]: Function definition with function as return type\n",
				LT(1).getLine());
		}
		function_definition_with_fun_as_ret_type
		{ #external_declaration = #(#[CSM_FUNCTION_RET_FUN_DEFINITION, "CSM_FUNCTION_RET_FUN_DEFINITION"], #external_declaration); }
	|
                asm_block
        |
		{isCPlusPlus()}?
		{if (statementTrace>=1) 
			printf("external_declaration_12[%d]: Namespace declaration\n",
				LT(1).getLine());
		}
		decl_namespace
		// moved to decl_namespace { #external_declaration = #(#[, ""], #external_declaration); }
        |
		{isCPlusPlus()}?
            // Constructor definition with initializer
            (   ctor_decl_spec ctor_declarator[true] COLON ) =>
            ctor_definition
            { #external_declaration = #(#[CSM_CTOR_DEFINITION, "CSM_CTOR_DEFINITION"], #external_declaration); }
	|	
		// everything else (except templates)
		{if (statementTrace>=1) 
			printf("external_declaration_13[%d]: Declaration\n",LT(1).getLine());
		}
                // VV: 23/05/06 support for gcc's "__extension__"
		(LITERAL___extension__!)?  declaration[declGeneric]
		{ 
		    // if declaration itself returned proper type, don't wrap it into generic declaration
		    if( #external_declaration != null ) {
			int type = #external_declaration.getType(); 
			int childrenCnt = #external_declaration.getNumberOfChildren();
			if( childrenCnt > 0 || type < CSM_START || CSM_END < type ) {
			    #external_declaration = #(#[CSM_GENERIC_DECLARATION, "CSM_GENERIC_DECLARATION"], #external_declaration);
			}
		    }
		}
	|	
		{if (statementTrace>=1) 
			printf("external_declaration_14[%d]: Semicolon\n",LT(1).getLine());
		}
		SEMICOLON! //{end_of_stmt();}
	)
	;	// end of external_declaration

decl_namespace
	{String qid; String name = "";}
	:	
		(literal_inline)? token:LITERAL_namespace
		(
                        {action.namespace_declaration(token);}
			(name = literal_ident{_td = true; /*declaratorID(name,qiType);} {action.namespace_name(name);*/})?

			// The following statement can be invoked to trigger selective
			// antlr trace. Also see below
			//{
			//	if (strcmp((ns.getText()),"xyz")==0) {
			//	    antlrTrace(true);
			//	 }	// Used for diagnostic trigger
			//}
			(options {greedy=true;} : namespace_attribute_specification)?
                        {action.namespace_body(LT(1));}
			LCURLY
			//{enterNewLocalScope();}
			((external_declaration)*)
			{/*exitLocalScope();*/{ #decl_namespace = #(#[CSM_NAMESPACE_DECLARATION, name], #decl_namespace); }}
                        {action.end_namespace_body(LT(1));}
			token2:RCURLY {action.end_namespace_declaration(token2);}
			// The following should be implemented to match the optional
			// statement above
			//{antlrTrace(false);}
		|
			name = literal_ident{_td = true;declaratorID((name),qiType);}
			ASSIGNEQUAL qid = qualified_id SEMICOLON! 
			{/*end_of_stmt();*/#decl_namespace = #(#[CSM_NAMESPACE_ALIAS, name], #decl_namespace);} 
		)                
	;

namespace_alias_definition
	{String qid; String name = "";}
	:
		lns:LITERAL_namespace
		name = literal_ident{_td = true;declaratorID((name),qiType);}
		lae:ASSIGNEQUAL 
        /*{action.namespace_alias_definition(lns, ns2, lae);}*/
        qid = qualified_id 
        /*{action.end_namespace_alias_definition(LT(1));}*/
        SEMICOLON!
		{#namespace_alias_definition = #(#[CSM_NAMESPACE_ALIAS, name], #namespace_alias_definition);}
	;

//
// it's a caller's responsibility to check isCPlusPlus
//
member_declaration_template
	{String q; boolean definition=false; boolean friend = false; boolean ctorName = false;}
	:
		{beginTemplateDefinition();}
		template_head
 		(     
			(class_head)=>
			{if (statementTrace>=1) 
				printf("member_declaration_12[%d]: Class template declaration\n",
					LT(1).getLine());
			}                           
			declaration[declOther]
			{ #member_declaration_template = #(#[CSM_TEMPLATE_CLASS_DECLARATION, "CSM_TEMPLATE_CLASS_DECLARATION"], #member_declaration_template); }
		|  
			// Templated FUNCTIONS and CONSTRUCTORS matched here.
			// DW 27/06/03 Copied here from external_declaration since templates
			// can now be nested

			// Templated CONSTRUCTOR declaration
                        (	ctor_decl_spec
                                {qualifiedItemIsOneOf(qiCtor)}?
                                ctor_declarator[false] (EOF|SEMICOLON)
                        )=>
                        {if (statementTrace>=1) 
                                printf("member_declaration_13[%d]: Constructor declarator\n",
                                        LT(1).getLine());
                        }
                        friend = ctor_decl_spec
                        ctorName = ctor_declarator[false] 	
                        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
                        | SEMICOLON ) // Constructor declarator
                        {
                        // below is a workaround for know infinite loop bug in ANTLR 
                        // see http://www.jguru.com/faq/view.jsp?EID=271922
                        //if( #cds1 != null ) { #cds1.setNextSibling(null); }; 
                        #member_declaration_template = #(#[CSM_CTOR_TEMPLATE_DECLARATION, "CSM_CTOR_TEMPLATE_DECLARATION"],  #member_declaration_template); //end_of_stmt();
                        }   

                  |

			// Templated CONSTRUCTOR definition
			// JEL 4/3/96 Added predicate that works once the
			// restriction is added that ctor cannot be virtual
			(ctor_decl_spec
			 {qualifiedItemIsOneOf(qiCtor)}?
			 ctor_declarator[true]
			 ( COLON        // DEFINITION :ctor_initializer
			  |LCURLY       // DEFINITION (compound Statement) ?
                          | ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
			 )
			)=>
			{if (statementTrace>=1) 
				printf("member_declaration_13a[%d]: Template constructor " +
					"definition\n", LT(1).getLine());
			}
			ctor_definition
			{ #member_declaration_template = #(#[CSM_CTOR_TEMPLATE_DEFINITION, "CSM_CTOR_TEMPLATE_DEFINITION"], #member_declaration_template); }
		|
			// Templated function declaration
			(declaration_specifiers[false, false] function_declarator[false, false, false] SEMICOLON)=>
			{if (statementTrace>=1) 
				printf("member_declaration_13b[%d]: Function template " +
					"declaration\n", LT(1).getLine());
			}
			declaration[declOther]
			{ #member_declaration_template = #(#[CSM_FUNCTION_TEMPLATE_DECLARATION, "CSM_FUNCTION_TEMPLATE_DECLARATION"], #member_declaration_template); }
    |
        // Templated function definition
        // Function definition DW 2/6/97
        (declaration_specifiers[false, false] function_declarator[true, false, false] (LCURLY | literal_try | ASSIGNEQUAL (LITERAL_default | LITERAL_delete)))=>
        {if (statementTrace>=1) printf("member_declaration_13c[%d]: Function template " + "definition\n", LT(1).getLine());}
        function_definition
        { #member_declaration_template = #(#[CSM_FUNCTION_TEMPLATE_DEFINITION, "CSM_FUNCTION_TEMPLATE_DEFINITION"], #member_declaration_template); }
    |
        (   ((options {greedy=true;} :function_attribute_specification)|literal_inline|LITERAL_constexpr|LITERAL_explicit)*
            conversion_function_decl_or_def
        ) =>
        {if (statementTrace>=1) printf("member_declaration_13d[%d]: Templated operator " + "function\n", LT(1).getLine());}
        ((options {greedy=true;} :function_attribute_specification)|literal_inline|LITERAL_constexpr|LITERAL_explicit)*
        definition = conversion_function_decl_or_def
        {if( definition )   #member_declaration_template = #(#[CSM_USER_TYPE_CAST_TEMPLATE_DEFINITION, "CSM_USER_TYPE_CAST_TEMPLATE_DEFINITION"], #member_declaration_template);
         else               #member_declaration_template = #(#[CSM_USER_TYPE_CAST_TEMPLATE_DECLARATION, "CSM_USER_TYPE_CAST_TEMPLATE_DECLARATION"], #member_declaration_template);}
    |
        (LITERAL_using literal_ident ASSIGNEQUAL) => alias_declaration
        { #member_declaration_template = #(#[CSM_FIELD, "CSM_FIELD"], #member_declaration_template); }
    |
                        // this rule must be after handling functions 
			// templated forward class decl, init/decl of static member in template
			(declaration_specifiers[true, false]
				(init_declarator_list[declOther])? SEMICOLON /*{end_of_stmt();}*/)=>
			//{beginTemplateDeclaration();}
			{ if (statementTrace>=1) 
				printf("member_declaration_12a[%d]: Class template declaration\n",
					LT(1).getLine());
			}
			declaration_specifiers[true, false]
				(init_declarator_list[declOther])? SEMICOLON //{end_of_stmt();}
			{/*endTemplateDeclaration();*/ #member_declaration_template = #(#[CSM_TEMPL_FWD_CL_OR_STAT_MEM, "CSM_TEMPL_FWD_CL_OR_STAT_MEM"], #member_declaration_template); } 		
		)
		{endTemplateDefinition();}

	;

member_declaration
	{String q; boolean definition;boolean ctrName=false;StorageClass sc = scInvalid;int ts = 0;boolean friend = false;}
	:
	(
		// Class definition
		// This is separated out otherwise the next alternative
		// would look for "class A { ... } f() {...}" which is
		// an unacceptable level of backtracking.
                // we need "static" here for the case "static struct XX {...} myVar; - see issue #135149

//		((LITERAL_typedef | LITERAL_static)? class_head)=>
        ((LITERAL___extension__!)? (decl_specifiers_before_type)? class_head) =>
        {action.simple_declaration(LT(1));}
        {action.class_declaration(LT(1));}
		{if (statementTrace>=1) 
			printf("member_declaration_1[%d]: Class definition\n",
				LT(1).getLine());
		}
		(LITERAL___extension__!)? declaration[declOther]
		{ #member_declaration = #(#[CSM_CLASS_DECLARATION, "CSM_CLASS_DECLARATION"], #member_declaration); }
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		((LITERAL___extension__!)? (decl_specifiers_before_type)? enum_def_head)=>
        {action.simple_declaration(LT(1));}
        {action.enum_declaration(LT(1));} 
		{if (statementTrace>=1) 
			printf("member_declaration_2[%d]: Enum definition\n",
				LT(1).getLine());
		}
		(LITERAL___extension__!)? declaration_specifiers[true, false] (member_declarator_list)? 
        {action.end_enum_declaration(LT(1));}
        {action.end_simple_declaration(LT(1));}
        SEMICOLON	//{end_of_stmt();}
		{ #member_declaration = #(#[CSM_ENUM_DECLARATION, "CSM_ENUM_DECLARATION"], #member_declaration); }
	|
		// Enum forward declaration (don't want to backtrack over this in other alts)
		((LITERAL___extension__!)? (decl_specifiers_before_type)? enum_fwd_head)=>
        {action.simple_declaration(LT(1));}
        {action.enum_declaration(LT(1));}
        (LITERAL___extension__!)? 
        (decl_specifiers_before_type)?
		{if (statementTrace>=1)
			printf("member_declaration_2b[%d]: Enum forward declaration\n",
				LT(1).getLine());
		}
		enum_specifier
        {action.end_enum_declaration(LT(1));}
        {action.end_simple_declaration(LT(1));}
        SEMICOLON	//{end_of_stmt();}
		{ #member_declaration = #(#[CSM_ENUM_FWD_DECLARATION, "CSM_ENUM_FWD_DECLARATION"], #member_declaration); }
	|	
		// Constructor declarator
		(	ctor_decl_spec
			/*{qualifiedItemIsOneOf(qiCtor)}?*/
			ctor_declarator[false] (EOF|SEMICOLON)
		)=>
		{if (statementTrace>=1) 
			printf("member_declaration_3[%d]: Constructor or no-ret type fun declarator\n",
				LT(1).getLine());
		}
		friend = cds:ctor_decl_spec
//                {ctrName = qualifiedItemIsOneOf(qiCtor);}
		ctrName = cd:ctor_declarator[false] 	(EOF!|SEMICOLON) // Constructor declarator
		{
                    // below is a workaround for know infinite loop bug in ANTLR 
                    // see http://www.jguru.com/faq/view.jsp?EID=271922
                    if( #cds != null ) { #cds.setNextSibling(null); }; 
                    if (ctrName && !friend) {
                        #member_declaration = #(#[CSM_CTOR_DECLARATION, "CSM_CTOR_DECLARATION"], #cds, #cd); //end_of_stmt();
                    } else {
                        #member_declaration = #(#[CSM_FUNCTION_DECLARATION, "CSM_FUNCTION_DECLARATION"], #cds, #cd); //end_of_stmt();
                    }
                }
    |
        // JEL Predicate to distinguish ctor from function
        // This works now that ctor cannot have VIRTUAL
        // It unfortunately matches A::A where A is not enclosing
        // class -- this will have to be checked semantically
        (   ctor_decl_spec
            /*{qualifiedItemIsOneOf(qiCtor)}?*/
            ctor_declarator[true]
            (COLON        // DEFINITION :ctor_initializer
            |LCURLY       // DEFINITION (compound Statement) ?
            |literal_try  // DEFINITION try ... catch ...
            | ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
            )
        )=>
        {if (statementTrace>=1) printf("member_declaration_4[%d]: Constructor or no-ret type fun definition\n", LT(1).getLine());}
        friend = ctor_decl_spec
//        {ctrName = qualifiedItemIsOneOf(qiCtor);}
        ctrName = ctor_declarator[true]
        (   ctor_body
        |   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
        )

        {if (ctrName && !friend) { #member_declaration = #(#[CSM_CTOR_DEFINITION, "CSM_CTOR_DEFINITION"], #member_declaration);}
         else { #member_declaration = #(#[CSM_FUNCTION_DEFINITION, "CSM_FUNCTION_DEFINITION"], #member_declaration);}}
    |
        // Destructor declarator
        // No template_head allowed for dtor member
        // Backtrack if not a dtor (no TILDE)
        (dtor_head[false] (EOF|SEMICOLON))=>
        {if (statementTrace>=1) 
                printf("member_declaration_5a[%d]: Destructor declaration\n",
                        LT(1).getLine());
        }
        // This is inlined dtor_head rule (here it is necessary to know if destructor is friend)
        friend = dtor_decl_spec        
        dtor_declarator[false]
        ( 
            EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | 
            SEMICOLON 
        ) //{end_of_stmt();}	// Declaration        
        {
            if (!friend) {
                #member_declaration = #(#[CSM_DTOR_DECLARATION, "CSM_DTOR_DECLARATION"], #member_declaration); //end_of_stmt();
            } else {
                #member_declaration = #(#[CSM_FUNCTION_DECLARATION, "CSM_FUNCTION_DECLARATION"], #member_declaration); //end_of_stmt();
            }
        }
    |
        // Destructor definition
        // No template_head allowed for dtor member
        // Backtrack if not a dtor (no TILDE)
        (   dtor_head[true] 
            (   LCURLY
            |   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
            )
        )=>
        {if (statementTrace>=1) 
                printf("member_declaration_5b[%d]: Destructor definition\n",
                        LT(1).getLine());
        }
		dtor_head[true] 
        (   dtor_body
        |   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
        )
	{ #member_declaration = #(#[CSM_DTOR_DEFINITION, "CSM_DTOR_DEFINITION"], #member_declaration); }
    |
        // Function declaration
        (   (LITERAL___extension__)?
            declaration_specifiers[false, false]
            function_declarator[false, false, false]
            (EOF|SEMICOLON)
        ) =>
        {if (statementTrace>=1) printf("member_declaration_6[%d]: Function declaration\n", LT(1).getLine());}
        declaration[declOther]
        { #member_declaration = #(#[CSM_FUNCTION_DECLARATION, "CSM_FUNCTION_DECLARATION"], #member_declaration); }
    |
        // Function definition
        (   (LITERAL___extension__)?
            declaration_specifiers[false, false]
            function_declarator[true, false, false]
            (LCURLY | literal_try | ASSIGNEQUAL (LITERAL_default | LITERAL_delete))
        ) =>
        {beginFieldDeclaration(); if(statementTrace>=1) printf("member_declaration_7[%d]: Function definition\n", LT(1).getLine());}
        function_definition
        { #member_declaration = #(#[CSM_FUNCTION_DEFINITION, "CSM_FUNCTION_DEFINITION"], #member_declaration); }
    |
        // Member without a type (I guess it can only be a function declaration or definition)
        ((LITERAL_static)? function_declarator[false, false, false] (EOF|SEMICOLON))=>
		{beginFieldDeclaration();
                if( reportOddWarnings ) {
                    printf("member_declaration[%d]: Warning Function declaration found without typename\n", LT(1).getLine());
                }
		if (statementTrace>=1) 
			printf("member_declaration_11a[%d]: Function declaration\n",
				LT(1).getLine());
		}
		(LITERAL_static)? function_declarator[false, false, false] 
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON ) //{end_of_stmt();}
		{ #member_declaration = #(#[CSM_FUNCTION_DECLARATION, "CSM_FUNCTION_DECLARATION"], #member_declaration); }
	|
		// Member without a type (I guess it can only be a function definition)
		((LITERAL_static)? function_declarator[true, false, false] LCURLY)=>
		{
                    if( reportOddWarnings ) {
                        printf("member_function[%d]: Warning Function definition found without typename\n", LT(1).getLine());
                    }
		    if (statementTrace>=1) {
			printf("member_declaration_11b[%d]: Function definition\n",
				LT(1).getLine());
		    }
		}
		(LITERAL_static)? function_declarator[true, false, false] compound_statement //{endFunctionDefinition();}
		{ #member_declaration = #(#[CSM_FUNCTION_DEFINITION, "CSM_FUNCTION_DEFINITION"], #member_declaration); }
        |       
                // function declaration with function as return type
		((LITERAL___extension__)? declaration_specifiers[false, false] function_declarator_with_fun_as_ret_type[false] (EOF|SEMICOLON))=> 
		{if (statementTrace>=1) 
			printf("external_declaration_7a[%d]: Function prototype with function as return type\n",
				LT(1).getLine());
		}
		function_declaration_with_fun_as_ret_type
		{ #member_declaration = #(#[CSM_FUNCTION_RET_FUN_DECLARATION, "CSM_FUNCTION_RET_FUN_DECLARATION"], #member_declaration); }
                
        |       // function definition with function as return type
                ((LITERAL___extension__)? declaration_specifiers[false, false] function_declarator_with_fun_as_ret_type[true] LCURLY)=> 
		{if (statementTrace>=1) 
			printf("external_declaration_8b[%d]: Function definition with function as return type\n",
				LT(1).getLine());
		}
		function_definition_with_fun_as_ret_type
		{ #member_declaration = #(#[CSM_FUNCTION_RET_FUN_DEFINITION, "CSM_FUNCTION_RET_FUN_DEFINITION"], #member_declaration); }
    |
        // User-defined type cast
        (   ((options {greedy=true;} :function_attribute_specification)|literal_inline|LITERAL_virtual|LITERAL_constexpr|LITERAL_explicit)*
            conversion_function_decl_or_def
        ) =>
        {if (statementTrace>=1) printf("member_declaration_8[%d]: Operator function\n", LT(1).getLine());}
        ((options {greedy=true;} :function_attribute_specification)|literal_inline|LITERAL_virtual|LITERAL_constexpr|LITERAL_explicit)*
        definition = conversion_function_decl_or_def
        {if( definition )   #member_declaration = #(#[CSM_USER_TYPE_CAST_DEFINITION, "CSM_USER_TYPE_CAST_DEFINITION"], #member_declaration);
         else               #member_declaration = #(#[CSM_USER_TYPE_CAST_DECLARATION, "CSM_USER_TYPE_CAST_DECLARATION"], #member_declaration);}
    |
        // Hack to handle decls like "superclass::member",
        // to redefine access to private base class public members
        (qualified_id (EOF|SEMICOLON))=>
        {if (statementTrace>=1) printf("member_declaration_9[%d]: Qualified literal_ident\n", LT(1).getLine());}
        visibility_redef_declaration
    |
		// Member with a type or just a type def
		// A::T a(), ::T a, ::B a, void a, E a (where E is the enclosing class)
		((LITERAL___extension__)? declaration_specifiers[true, false])=>
		{beginFieldDeclaration();
		 if (statementTrace>=1) 
			printf("member_declaration_10[%d]: Declaration(s)\n",
				LT(1).getLine());
		}
		(LITERAL___extension__!)? declaration_specifiers[true, false] (member_declarator_list)? 
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON) //{end_of_stmt();}
                // now member typedefs are placed under CSM_FIELD, so we do this here as well
                // TODO: separate imaginery AST nodes for typedefs and fields
		{ #member_declaration = #(#[CSM_FIELD, "CSM_FIELD"], #member_declaration); }
	|  
		{isCPlusPlus()}? ((LITERAL_export)? LITERAL_template) => member_declaration_template
	|  
		{if (statementTrace>=1) 
			printf("member_declaration_14[%d]: Access specifier\n",
			    LT(1).getLine());
		}
		access_specifier COLON!
	|  
		{if (statementTrace>=1) 
			printf("member_declaration_15[%d]: Semicolon\n",
				LT(1).getLine());
		}
		SEMICOLON! //{end_of_stmt();}
        |       (LITERAL_using literal_ident ASSIGNEQUAL) => alias_declaration
                { #member_declaration = #(#[CSM_FIELD, "CSM_FIELD"], #member_declaration); }
	|	using_declaration
        |       static_assert_declaration
	)
	;	// end member_declaration

// FIXUP: till qualifiedItemIsOneOf(qiType | qiCtor) is not correct in function_definition
function_definition_no_ret_type
	:	// don't want next action as an init-action due to (...)=> caller
	//{ beginFunctionDefinition(); }
	(	// Next line is equivalent to guarded predicate in PCCTS
		function_declarator[true, false, false]
		(	options{warnWhenFollowAmbig = false;}:
			//(declaration)*	// Possible for K & R definition
                        (function_K_R_parameter_list)?
			{in_parameter_list = false;}
		)
		compound_statement
	)
	//{endFunctionDefinition();}
	;

function_declarator_with_fun_as_ret_type  [boolean definition]
        :
                (ptr_operator)=> ptr_operator function_declarator_with_fun_as_ret_type[definition]
            |
                LPAREN function_declarator[definition, false, false] RPAREN 
                function_params
                (options{greedy = true;} : fun_cv_qualifier_seq)? // TODO: check if here could be cv qualifiers
                (options{greedy = true;} : ref_qualifier)?        // TODO: check if here could be ref qualifier
                (exception_specification)?
        ;
    
function_declaration_with_fun_as_ret_type
        :
            declaration_specifiers[false, false] function_declarator_with_fun_as_ret_type[false] 
            ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
            | SEMICOLON )
        ;

function_definition_with_fun_as_ret_type
        :
		declaration_specifiers[false, false] function_declarator_with_fun_as_ret_type[true]
		(	options{warnWhenFollowAmbig = false;}:
			//(declaration)*	// Possible for K & R definition
                        (function_K_R_parameter_list)?
			{in_parameter_list = false;}
		)?
		compound_statement

        ;

protected
function_K_R_parameter_list
    :
    (function_K_R_parameter)+
    {#function_K_R_parameter_list = #(#[CSM_KR_PARMLIST, "CSM_KR_PARMLIST"], #function_K_R_parameter_list);}
    ;

protected
function_K_R_parameter
    :
    declaration[declFunctionParam]
    {#function_K_R_parameter=#(#[CSM_PARAMETER_DECLARATION, "CSM_PARAMETER_DECLARATION"], #function_K_R_parameter);}
    ;

function_definition
    :
    // don't want next action as an init-action due to (...)=> caller
    // IZ 132404 : Parser failed on code taken from boost
    //	//{ beginFunctionDefinition(); }
    //	(	// Next line is equivalent to guarded predicate in PCCTS
    //		// (SCOPE | literal_ident)? => <<qualifiedItemIsOneOf(qiType|qiCtor)>>?
    //              {( !(LA(1)==SCOPE || LA(1)==literal_ident) || qualifiedItemIsOneOf(qiType | qiCtor) )}?
    declaration_specifiers[false, false]
    (options {greedy=true;} :function_attribute_specification!)?
    function_declarator[true, false, false]
    (   options{warnWhenFollowAmbig = false;}:
        //(declaration)*	// Possible for K & R definition
        (function_K_R_parameter_list)?
        {in_parameter_list = false;}
    )?
    (   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
    |   compound_statement
    |   function_try_block[false]
    )
    //	|	// Next line is equivalent to guarded predicate in PCCTS
    //		// (SCOPE | literal_ident)? => <<qualifiedItemIsOneOf(qiPtrMember)>>?
    //		//{( !(LA(1)==SCOPE||LA(1)==literal_ident) || (qualifiedItemIsOneOf(qiPtrMember)) )}?
    //		function_declarator[true]
    //		(	options{warnWhenFollowAmbig = false;}:
    //			(declaration)*	// Possible for K & R definition
    //			{in_parameter_list = false;}
    //		)?
    //                compound_statement
    //	)
    //	//{endFunctionDefinition();}
    ;

// rule for predicting "declaration"
// must be updated together with declaration rule
protected
is_declaration
        :
        LITERAL_extern | LITERAL_using | (declaration_specifiers[true, false] declarator[declOther, 0])
        ;

declaration[int kind]
    :
        (LITERAL_extern STRING_LITERAL)=> linkage_specification
    |
        {kind == declExternFunction}? (LITERAL_extern) =>
        {beginDeclaration();}
        LITERAL_extern
        ((COMMA!)? init_declarator_list[kind])?
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON )
        {endDeclaration();}
    |
        {kind == declSimpleFunction}? (literal_ident LPAREN) =>
        {beginDeclaration();}
        init_declarator_list[kind]
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON )
        {endDeclaration();}
    |
        {beginDeclaration();}
        
        // LL 31/1/97: added (COMMA) ? below. This allows variables to
        // typedef'ed more than once. DW 18/08/03 ?
        {action.decl_specifiers(LT(1));}
        declaration_specifiers[true, false] 
        {action.end_decl_specifiers(LT(0));}

        ((COMMA!)? init_declarator_list[kind])?
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON )
        //{end_of_stmt();}
        {endDeclaration();}
    |
        (LITERAL_using literal_ident ASSIGNEQUAL) => alias_declaration
    |
	using_declaration	// DW 19/04/04
    |
        namespace_alias_definition
    |
        static_assert_declaration
    ;

linkage_specification
	:	LITERAL_extern STRING_LITERAL
		(	LCURLY (external_declaration)* RCURLY
		|	external_declaration
		)
		{ #linkage_specification = #(#[CSM_LINKAGE_SPECIFICATION,"CSM_LINKAGE_SPECIFICATION"], #linkage_specification);}
	;

declaration_specifiers [boolean allowTypedef, boolean noTypeId]
{
    // Global flags to allow for nested declarations
    _td = false;        // For typedef
    _fd = false;        // For friend
    _sc = scInvalid;    // For StorageClass
    _tq = tqInvalid;    // For TypeQualifier
    _ts = tsInvalid;    // For TypeSpecifier
    _ds = dsInvalid;    // For DeclSpecifier


    // Locals
    boolean td = false; // For typedef
    boolean fd = false; // For friend
    StorageClass sc = scInvalid;        // auto,register,static,extern,mutable
    TypeQualifier tq = tqInvalid;       // const,const_cast,volatile,cdecl
    /*TypeSpecifier*/int ts = tsInvalid;// char,int,double, etc., class,struct,union
    DeclSpecifier ds = dsInvalid;       // inline,virtual,explicit
}
:
(
    // fix for unknown specifiers
    unknown_pretype_declaration_specifiers

    ((LITERAL_static literal_ident (SEMICOLON | ASSIGNEQUAL | COMMA)) =>
        sc = storage_class_specifier
    |
        (   ( (LITERAL_constexpr | cv_qualifier | LITERAL_static | literal_inline | LITERAL_friend)* 
              LITERAL_auto 
              (postfix_cv_qualifier | LITERAL_constexpr)? 
              (literal_inline | storage_class_specifier | LITERAL_virtual)*
              declarator[declOther, 0]) => 
            (LITERAL_constexpr | tq = cv_qualifier | LITERAL_static | literal_inline | LITERAL_friend)*
        |
            (   options {warnWhenFollowAmbig = false;} : 
                {isCPlusPlus11()}? sc = cpp11_storage_class_specifier
            |   {!isCPlusPlus11()}? sc = storage_class_specifier
            |   tq = cv_qualifier 
            |   literal_inline {ds = dsINLINE;}
            |   LITERAL__Noreturn
            |   LITERAL_virtual {ds = dsVIRTUAL;}
            |   LITERAL_explicit {ds = dsEXPLICIT;}
            |   LITERAL_final
//              Here we could include enum and handle creating of enums on declaration level with predicates
//              This may be better because we will not accept enums in return types and parameters in such case
//          |   LITERAL_enum  
            |   {if (statementTrace>=1) printf("declaration_specifiers_1[%d]: Typedef\n", LT(1).getLine());}                        
                {allowTypedef}? LITERAL_typedef (options {greedy=true;} : LITERAL_typename)? {td=true;} 
            |   LITERAL_typename
            |   LITERAL_friend {fd=true;}
            |   LITERAL_constexpr
            |   literal_stdcall
            |   literal_clrcall
            |   (options {greedy=true;} : type_attribute_specification!)
            )*
        ) 
        (
            (options {greedy=true;} :type_attribute_specification)?
            ts = type_specifier[ds, noTypeId]
            // support for "A const*";
            // need to catch postfix_cv_qualifier
            (postfix_cv_qualifier | LITERAL_constexpr)? 
            (
                (literal_inline {ds = dsINLINE;})
            |
                (sc = storage_class_specifier)
            | 
                LITERAL_virtual
            )*
            (options {greedy=true;} :type_attribute_specification)?

            // fix for unknown specifiers
            unknown_posttype_declaration_specifiers

    //  |   LITERAL_typename	{td=true;}	direct_declarator 
        |   literal_typeof LPAREN typeof_param RPAREN
        )
    )
    ({allowTypedef}? LITERAL_typedef {td=true;})?
)
{declarationSpecifier(td, fd, sc, tq, ts, ds);}
;

unknown_pretype_declaration_specifiers
    {String s;}
    :
    unknown_pretype_declaration_specifiers_list
    ((literal_ident 
        (
            LITERAL_friend | LITERAL_typedef | LITERAL_virtual | LITERAL_explicit | LITERAL_final 
        |   LITERAL_enum | LITERAL_typename | literal_stdcall | literal_clrcall
        |   (postfix_cv_qualifier | LITERAL_constexpr | literal_inline | storage_class_specifier)* literal_ident 
            (postfix_cv_qualifier | LITERAL_constexpr | literal_inline | storage_class_specifier)* literal_ident
        )
    ) => s=literal_ident!)?
    ;

unknown_pretype_declaration_specifiers_list
    {String s;}
    :
    ((literal_ident literal_ident literal_ident) => s=literal_ident! unknown_pretype_declaration_specifiers_list)?
    ;

unknown_posttype_declaration_specifiers
    :
    unknown_posttype_declaration_specifiers_list
    ;

unknown_posttype_declaration_specifiers_list 
    {String s;}
    :
    ((literal_ident literal_ident) => s=literal_ident! unknown_posttype_declaration_specifiers_list)?
    ;

decl_specifiers_before_type
    {StorageClass sc; TypeQualifier tq;}
    :
        (
            sc = storage_class_specifier
        |
            tq = cv_qualifier
        |
            LITERAL_friend
        |
            LITERAL_constexpr
        |
            LITERAL_typedef
        )+
    ;

protected
typeof_param :
            // fast check of simple typeof (type) but skip typeof (type1() + type2()) which would be considered as expression
            (type_name {LA(1) != PLUS}?) => type_name
        |
            expression
        ;


storage_class_specifier returns [CPPParser.StorageClass sc = scInvalid]
    :
        LITERAL_auto {sc = scAUTO;}
    |
        sc = common_storage_class_specifier
    ;

cpp11_storage_class_specifier returns [CPPParser.StorageClass sc = scInvalid]
    :
        sc = common_storage_class_specifier
    ;

common_storage_class_specifier returns [CPPParser.StorageClass sc = scInvalid]
    :
        LITERAL_register    {sc = scREGISTER;}
    |   LITERAL_static      {sc = scSTATIC;}
    |   LITERAL_extern      {sc = scEXTERN;}
    |   LITERAL_mutable     {sc = scMUTABLE;}
    |   LITERAL___thread    {sc = scTHREAD;}
    |   LITERAL__STORAGE_CLASS_SPECIFIER__ {sc = scOTHER;}
    |   LITERAL___symbolic {sc = scOTHER;}
    |   LITERAL___global {sc = scOTHER;}
    |   LITERAL___hidden {sc = scOTHER;}
    |   LITERAL_thread_local {sc = scOTHER;}
    ;

cv_qualifier returns [CPPParser.TypeQualifier tq = tqInvalid] // aka cv_qualifier
	:  (literal_const|LITERAL_const_cast)	{tq = tqCONST;} 
	|  literal_volatile			{tq = tqVOLATILE;}
	|  LITERAL__TYPE_QUALIFIER__    {tq = tqOTHER;}
	;

ref_qualifier
    :
        AMPERSAND | AND
    ;

type_specifier[DeclSpecifier ds, boolean noTypeId] returns [/*TypeSpecifier*/int ts = tsInvalid]
:   ts = simple_type_specifier[noTypeId]
|   ts = class_specifier[ds]
|   enum_specifier {ts=tsENUM;}
|   LITERAL_auto {ts=tsAUTO;}
    { #type_specifier = #([CSM_TYPE_BUILTIN, "CSM_TYPE_BUILTIN"], #type_specifier); }
;

simple_type_specifier[boolean noTypeId] returns [/*TypeSpecifier*/int ts = tsInvalid]
	:	(	{!noTypeId && qualifiedItemIsOneOf(qiType|qiCtor)}? 
			qualified_type {ts=tsTYPEID;}	
			{ #simple_type_specifier = #([CSM_TYPE_COMPOUND, "CSM_TYPE_COMPOUND"], #simple_type_specifier); }
		|	
                        ts = builtin_cv_type_specifier[ts]
			{ #simple_type_specifier = #([CSM_TYPE_BUILTIN, "CSM_TYPE_BUILTIN"], #simple_type_specifier); }
		|
                        {!noTypeId}?
			// Fix towards allowing us to parse *.cpp files directly
			
                        // IZ 132404 : Parser failed on code taken from boost
                        //(qualified_type qualified_id)=> qualified_type { ts=tsTYPEID; }
                        (qualified_type) => qualified_type { ts=tsTYPEID; }
			
                        { #simple_type_specifier = #([CSM_TYPE_COMPOUND, "CSM_TYPE_COMPOUND"], #simple_type_specifier); }
		)
	;

builtin_cv_type_specifier[/*TypeSpecifier*/int old_ts] returns [/*TypeSpecifier*/int ts = old_ts]
{TypeQualifier tq;StorageClass sc;}
    :
        (options{greedy = true;}: ts = builtin_type[ts])+
        ((cv_qualifier builtin_type[ts]) => 
        tq = cv_qualifier ts = builtin_cv_type_specifier[ts])?
        ((storage_class_specifier builtin_type[ts]) => 
        sc = storage_class_specifier ts = builtin_cv_type_specifier[ts])?
        ((LITERAL_virtual builtin_type[ts]) => 
        LITERAL_virtual ts = builtin_cv_type_specifier[ts])?
    ;

builtin_type[/*TypeSpecifier*/int old_ts] returns [/*TypeSpecifier*/int ts = old_ts]
    :
	  LITERAL_char          {ts |= tsCHAR;}
        | LITERAL_wchar_t       {ts |= tsWCHAR_T;}  
        | LITERAL_char16_t      {ts |= tsOTHER;}
        | LITERAL_char32_t      {ts |= tsOTHER;}
        | LITERAL_bool          {ts |= tsBOOL;}
        | LITERAL__Bool         {ts |= tsBOOL;}
        | LITERAL_short         {ts |= tsSHORT;}
        | LITERAL_int           {ts |= tsINT;}
        | literal_int64         {ts |= tsLONG;}
        | LITERAL___w64         {ts |= tsLONG;}
        | LITERAL_long          {ts |= tsLONG;}
        | literal_signed        {ts |= tsSIGNED;}
        | literal_unsigned      {ts |= tsUNSIGNED;}
        | LITERAL_float         {ts |= tsFLOAT;}
        | LITERAL_double        {ts |= tsDOUBLE;}
        | LITERAL_void          {ts |= tsVOID;}
        | literal_complex       {ts |= tsCOMPLEX;}
        | LITERAL__Imaginary    {ts |= tsIMAGINARY;}
        | LITERAL_bit           {ts |= tsBOOL;}
        | LITERAL__BUILT_IN_TYPE__ {ts |= tsOTHER;}
        | LITERAL___builtin_va_list {ts |= tsOTHER;}
//        | literal_decltype LPAREN expression RPAREN {ts |= tsOTHER;}

    ;

qualified_type
	{String s;}
	: 
		// JEL 3/29/96 removed this predicate and moved it upwards to
		// simple_type_specifier.  This was done to allow parsing of ~literal_ident to 
		// be a unary_expression, which was never reached with this 
		// predicate on
		// {qualifiedItemIsOneOf(qiType|qiCtor)}?

		s = scope_override
        
        (s = literal_ident | type_decltype)
        
//                {if(s.isEmpty()) {action.simple_type_id(id);} }
//                {if(s.isEmpty()) {action.id(id);} }
		(options {warnWhenFollowAmbig = false;}:
		 LESSTHAN template_argument_list GREATERTHAN
		)?
	;

class_specifier[DeclSpecifier ds] returns [/*TypeSpecifier*/int ts = tsInvalid]
    {String saveClass = ""; String id = ""; StorageClass sc = scInvalid;}
    :   
        {action.class_kind(LT(1));}
        (   LITERAL_class  {ts = tsCLASS;}
        |   LITERAL_struct {ts = tsSTRUCT;}
        |   LITERAL_union  {ts = tsUNION;}
        )
        (options {greedy=true;} : type_attribute_specification)?
        (sc = storage_class_specifier!)?
        (   id = class_qualified_id
            (options{generateAmbigWarnings = false;}:
                (LITERAL_final | LITERAL_explicit)?
                (base_clause)?                
                // parse class body if nesting limit not exceed
                (
                    {checkClassDefinitionDepth(NESTED_CLASSES_LIMIT)}?
                        {
                            saveClass = enclosingClass;
                            enclosingClass = id;
                        }
                        {action.class_body(LT(1));}
                        LCURLY
                        // This stores class name in dictionary
                        {beginClassDefinition(ts, id);}
                        class_members
                        {endClassDefinition();}
                        {enclosingClass = saveClass;}
                        {action.end_class_body(LT(1));}
                        {action.end_class_declaration(LT(1));}
                        {action.end_simple_declaration(LT(1));}
                        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
                        | RCURLY )
                    |   
                        balanceCurlies
                )
            |
                {classForwardDeclaration(ts, ds, id);}
            )
        |
            (   
                {checkClassDefinitionDepth(NESTED_CLASSES_LIMIT)}?
                    {action.class_body(LT(1));}
                    LCURLY
                    {saveClass = enclosingClass; enclosingClass = (String ) "__anonymous";}
                    {beginClassDefinition(ts, "anonymous");}
                    (member_declaration)*
                    {endClassDefinition();}
                    {action.end_class_body(LT(1));}
                    {action.end_class_declaration(LT(1));}
                    {action.end_simple_declaration(LT(1));}
                    ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
                    | RCURLY )
                    {enclosingClass = saveClass;}
                |     
                    balanceCurlies
            )
        )
    ;

class_members
    :
    (options{generateAmbigWarnings = false;greedy=false;}:
        member_declaration
    |
        // IZ 136081 : Wrong parser recovering in class
        balanceCurlies { reportError(new NoViableAltException(LT(0), getFilename())); }
    |
        // IZ 138291 : Completion does not work for unfinished constructor
        // On unfinished construction we skip some symbols for class parsing process recovery
        (~(LCURLY))! { reportError(new NoViableAltException(LT(0), getFilename())); }
    )*
    ;

fix_fake_class_members
    :
        class_members
        { #fix_fake_class_members = #(#[CSM_CLASS_DECLARATION, "CSM_CLASS_DECLARATION"], #fix_fake_class_members); }
    ;

fix_fake_enum_members
    :
        enumerator_list
        { #fix_fake_enum_members = #(#[CSM_ENUM_DECLARATION, "CSM_ENUM_DECLARATION"], #fix_fake_enum_members); }
    ;

enum_specifier
{int ts = 0;
 String qid;}
:   LITERAL_enum
    (options {greedy=true;} : type_attribute_specification)?
    (
        (LITERAL_class | LITERAL_struct)
        {action.enum_strongly_typed(LT(1));}
    )?
    (   (COLON ts = builtin_cv_type_specifier[ts])?
        (type_attribute_specification)?
        LCURLY enumerator_list 
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | RCURLY )
    |   
        qid = enum_qualified_id
        // elaborated_type_specifier        
        (   (options {greedy=true;} : 
                COLON ts = type_specifier[dsInvalid, false]
            )?
            (options {greedy=true;} :
                {action.enum_body(LT(1));}
                        (type_attribute_specification)?
                LCURLY enumerator_list 
                {action.end_enum_body(LT(1));}
                ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
                | RCURLY )
            )?
        )
    {endEnumDefinition();}
    )
;

enum_qualified_id returns [String qid = ""]
    :
            (SCOPE literal_ident ) =>
            qid = qualified_id
        |
            (literal_ident (SCOPE | LESSTHAN) ) =>
            qid = qualified_id
        |
            qid = literal_ident     // DW 22/04/03 Suggest qualified_id here to satisfy
//            {qid = id.getText();}
            {#enum_qualified_id = #(#[CSM_QUALIFIED_ID, qid], #enum_qualified_id);}
    ;

enumerator_list
    :           
                enumerator
                ( options {greedy=true;} : (COMMA!) enumerator )*  
                (COMMA!)?
		{ #enumerator_list = #(#[CSM_ENUMERATOR_LIST, "CSM_ENUMERATOR_LIST"], #enumerator_list); }           
    | 
    ;

enumerator
    {String id = "";}
	:	id = literal_ident (ASSIGNEQUAL constant_expression)?
        /*{action.enumerator(id);}*/
//		{enumElement(id.getText());}
	;

/* This matches a generic qualified identifier ::T::B::foo
 * (including LITERAL_OPERATOR).
 * It might be a good idea to put T::~dtor in here
 * as well, but id_expression in expr.g puts it in manually.
 * Maybe not, 'cause many people use this assuming only A::B.
 * How about a 'qualified_complex_id'?
 */
qualified_id returns [String q = ""]
	{
	    String so, id;
	    StringBuilder qitem = new StringBuilder();
	}
	:
    (literal_cdecl)?
	so = scope_override { qitem.append(so); }
	(  
		id = literal_ident	(options{warnWhenFollowAmbig = false;}:
				 LESSTHAN template_argument_list GREATERTHAN)?
                //{action.simple_template_id_or_ident(id);}
                //{action.using_directive(action.USING_DIRECTIVE__IDENT, id);}
		{qitem.append(id);}
		|  
		LITERAL_OPERATOR optor (options{warnWhenFollowAmbig = false;}:
				 LESSTHAN template_argument_list GREATERTHAN)?
		{qitem.append("operator"); qitem.append("NYI");} // TODO: understand
		|
		LITERAL_OPERATOR STRING_LITERAL id=literal_ident (options{warnWhenFollowAmbig = false;}:
				 LESSTHAN template_argument_list GREATERTHAN)?
		{qitem.append("operator"); qitem.append("NYI");} // TODO: understand
		|
		LITERAL_this  // DW 21/07/03 fix to pass test8.i
		|
		(LITERAL_true|LITERAL_false)	// DW 21/07/03 fix to pass test8.i
	)
	{q = qitem.toString(); #qualified_id = #(#[CSM_QUALIFIED_ID, q], #qualified_id);}
	;

unqualified_id returns [String q = ""]
	{
	    String so, id;
	    StringBuilder qitem = new StringBuilder();
	}
	:
	so = scope_override {qitem.append(so);}
	(  
		id = literal_ident (options{warnWhenFollowAmbig = false;}:
                 LESSTHAN template_argument_list GREATERTHAN)?
        //{action.simple_template_id_or_ident(id);}
		{qitem.append(id);}
    |  
        LITERAL_OPERATOR 
        (
            (optor) => // predicate to avoid nondeterminism between optor and declaration_specifiers
                optor (options{warnWhenFollowAmbig = false;}: 
                        LESSTHAN template_argument_list GREATERTHAN)?
                {qitem.append("operator"); qitem.append("NYI");} // TODO: understand
        |
            STRING_LITERAL id=literal_ident (options{warnWhenFollowAmbig = false;}:
                    LESSTHAN template_argument_list GREATERTHAN)?
            {qitem.append("operator"); qitem.append("NYI");} // TODO: understand
        |
            declaration_specifiers[false, false]
            (ptr_operator)?
            (options{warnWhenFollowAmbig = false;}:
                LESSTHAN template_parameter_list GREATERTHAN)?
            {qitem.append("operator"); qitem.append("NYI");} // TODO: understand            
        )
    |
		LITERAL_this  // DW 21/07/03 fix to pass test8.i
    |
		(LITERAL_true|LITERAL_false)	// DW 21/07/03 fix to pass test8.i
	)
	{q = qitem.toString(); #unqualified_id = #(#[CSM_QUALIFIED_ID, q], #unqualified_id);}
	;


class_qualified_id returns [String q = ""]
{
    String so;
    String id;
    StringBuilder qitem = new StringBuilder();
}
:
    so =  scope_override { qitem.append(so); }
    (  
            id = literal_ident
//        { if(so.isEmpty()) action.class_name(id);} }
            (options{warnWhenFollowAmbig = false;}:
            LESSTHAN template_argument_list GREATERTHAN)?
            {qitem.append(id);}
        |  
            LITERAL_OPERATOR optor (options{warnWhenFollowAmbig = false;}:
            LESSTHAN template_argument_list GREATERTHAN)?
            {qitem.append("operator"); qitem.append("NYI");} // TODO: understand
        |
            LITERAL_this  // DW 21/07/03 fix to pass test8.i
        |
            (LITERAL_true|LITERAL_false) // DW 21/07/03 fix to pass test8.i
    )
    {q = qitem.toString(); #class_qualified_id = #(#[CSM_QUALIFIED_ID, q], #class_qualified_id);}
;

typeID
    {String s;}
	:	{isTypeName((LT(1).getText()))}?
		s=literal_ident
	;

init_declarator_list[int kind]
	:	init_declarator[kind] (COMMA init_declarator[declNotFirst])*
	;

init_declarator[int kind]
	:	declarator[kind, 0]
		(	
			ASSIGNEQUAL 
            (cast_array_initializer_head) => initializer
        |	
            LPAREN (expression_list | array_initializer) RPAREN
        |
            array_initializer
		)?
	;

initializer
    {String s;}
    : 
        // GCC designated initializer
        (literal_ident COLON)=>
            s=literal_ident 
            COLON 
            (options {greedy=true;} : initializer)? 
    |
        array_initializer
    |
        (   
            ((LITERAL___extension__)? cast_array_initializer_head) => 
                (LITERAL___extension__)? 
                cast_array_initializer 
                (options {greedy=true;} : lazy_expression[false, false, 0])?
        |
            lazy_expression[false, false, 0]
        )
        (options {greedy=true;}:	
            ( ASSIGNEQUAL
            | TIMESEQUAL
            | DIVIDEEQUAL
            | MINUSEQUAL
            | PLUSEQUAL
            | MODEQUAL
            | SHIFTLEFTEQUAL
            | SHIFTRIGHTEQUAL
            | BITWISEANDEQUAL
            | BITWISEXOREQUAL
            | BITWISEOREQUAL
            )            
            initializer
        )?
    ;

cast_array_initializer:
    // it's better to have LPAREN type RPAREN, but we use simple balanceParensInExpression
    (AMPERSAND)? (balanceParensInExpression)+ array_initializer
    ;

array_initializer:
        LCURLY RCURLY
    |   
        LCURLY initializer (ELLIPSIS)?
        (
            // empty comma
            (COMMA (RCURLY|EOF)) => COMMA
            |
            COMMA initializer (ELLIPSIS)?
        )*  
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | RCURLY )
    ;

// only for predicates
cast_array_initializer_head
:
    (AMPERSAND)? (balanceParensInExpression)* LCURLY
    ;

// so far this one is used in predicates only
class_head     
        { String s; StorageClass sc = scInvalid; }
	:	// Used only by predicates	
    (   LITERAL_struct  
    |	LITERAL_union 
    |	LITERAL_class)
    (options {greedy=true;} : type_attribute_specification)?
    (sc = storage_class_specifier)?
	(
        s = scope_override  
        s = literal_ident	
        (LESSTHAN template_argument_list GREATERTHAN)?
        (LITERAL_final | LITERAL_explicit)?
        (base_clause)? 
	)? LCURLY
	;

// for predicates
enum_head
    { String s; int ts; }
    :
        LITERAL_enum 
        (options {greedy=true;} : type_attribute_specification)?
        (LITERAL_class | LITERAL_struct)? 
        (s = enum_qualified_id)? 
        (COLON ts = type_specifier[dsInvalid, false])?
    ;

// for predicates
enum_def_head
    :
        enum_head LCURLY
    ;

// for predicates
enum_fwd_head
    :
        enum_head SEMICOLON        
    ;

// so far this one is used in predicates only
class_forward_declaration
        { String s; }
	:	// Used only by predicates
	(   LITERAL_struct
	|	LITERAL_union
	|	LITERAL_class)
    (options {greedy=true;} : type_attribute_specification)?
	(
        s = scope_override
        s = literal_ident
		(LESSTHAN template_argument_list GREATERTHAN)?
        (LITERAL_final | LITERAL_explicit)?
		(base_clause)?
	)? SEMICOLON
	;

protected
typedef_class_fwd
{ String id = "", td = ""; }
    :
    LITERAL_typedef
	(
		LITERAL_struct
	|	LITERAL_union
	|	LITERAL_class
	)
    id = qualified_id
    td = qualified_id
    SEMICOLON
;

base_clause
	:	COLON base_specifier (ELLIPSIS)? (COMMA base_specifier (ELLIPSIS)? )*
	;

base_specifier
	:	// DW 13/08/03 Should check qualified_type for class-name?
	(	LITERAL_virtual (access_specifier)? qualified_type 
	|	access_specifier (LITERAL_virtual)? qualified_type
	|	qualified_type
	)
	{#base_specifier=#(#[CSM_BASE_SPECIFIER,"CSM_BASE_SPECIFIER"], #base_specifier);}
	;

access_specifier
	:	LITERAL_public
	|	LITERAL_protected
	|	LITERAL_private
	;

member_declarator_list
	:	member_declarator
		(COMMA member_declarator)*
	;

member_declarator
    {String s;}
	:	
		((literal_ident)? COLON constant_expression)=>(s=literal_ident)? COLON constant_expression
    |
		init_declarator[declOther] 
	;

conversion_function_head
    {CPPParser.TypeQualifier tq; }
    :
        LITERAL_OPERATOR declaration_specifiers[true, false]
        (ptr_operator)*
        (LESSTHAN template_parameter_list GREATERTHAN)?
        LPAREN (parameter_list[false])? RPAREN	
        (tq = cv_qualifier)*
        (ref_qualifier)?
        (exception_specification)?
        (virt_specifiers)?
    ;

conversion_function_decl 
    :
        conversion_function_head
        SEMICOLON!
    ;

conversion_function_decl_or_def returns [boolean definition = false]
	:	// DW 01/08/03 Use type_specifier here? see syntax
		conversion_function_head
		(	compound_statement { definition = true; }
                    |	
                        ((conversion_function_special_definition)=> definition = conversion_function_special_definition)?
                        SEMICOLON! //{end_of_stmt();}
		)
	;

protected
conversion_function_special_definition returns [boolean definition = false]
    :         
        ASSIGNEQUAL
        (
               OCTALINT
           |
               LITERAL_delete { definition = true; }
        )
    ;

fun_cv_qualifier_seq
    {CPPParser.TypeQualifier tq;}
    :
        // IZ#134182 : missed const in function parameter
        // we should add "const" to function only if it's not K&R style function
        (   ((cv_qualifier)* 
             (is_post_declarator_token | LITERAL_throw | LITERAL_noexcept | literal_attribute | POINTERTO | 
              LITERAL_override | LITERAL_final | LITERAL_new | AMPERSAND | AND))
            =>
            (options{warnWhenFollowAmbig = false;}: tq = cv_qualifier)* 
        )?
    ;

// JEL note:  does not use (const|volatile)* to avoid lookahead problems
cv_qualifier_seq
	{TypeQualifier tq;}
	:
	(options {warnWhenFollowAmbig = false;}:tq = cv_qualifier)*
	;

declarator[int kind, int level]
    :
        // Fix for IZ#136947: IDE highlights code with 'typedef' as wrong
        // This rule adds support for declarations like
        // void (__attribute__((noreturn)) ****f) (void);
        {level < 5}? (attribute_specification)=> attribute_specification!
        declarator[kind, level + 1]
    |   //{( !(LA(1)==SCOPE||LA(1)==literal_ident) || qualifiedItemIsOneOf(qiPtrMember) )}?
        // VV: 23/05/06 added support for __restrict after pointers
        //i.e. void foo (char **__restrict a)
        {level < 5}? (ptr_operator)=> ptr_operator // AMPERSAND or STAR
        restrict_declarator[kind, level + 1]
    |
        // typedef ((...));
        // int (i);
        // or
        // type(var);
        {level < 5 && (_td || (_ts != tsInvalid))}? (LPAREN declarator[kind, level + 1] RPAREN is_post_declarator_token) =>
        LPAREN declarator[kind, level + 1] RPAREN
    |
        // type (var) = {...}
        {level < 5}? (LPAREN declarator[kind, level + 1] RPAREN ASSIGNEQUAL LCURLY) =>
        LPAREN declarator[kind, level + 1] RPAREN
    |
        {level < 5}? direct_declarator[kind, level + 1]
    ;

restrict_declarator[int kind, int level]
{CPPParser.TypeQualifier tq; }
    :
        // IZ 109079 : Parser reports "unexpexted token" on parenthesized pointer to array
        // IZ 140559 : parser fails on code from boost
        (LPAREN declarator[kind, level] RPAREN is_post_declarator_token) =>
        LPAREN declarator[kind, level] RPAREN
    |
        // Fix for IZ#136947: IDE highlights code with 'typedef' as wrong
        // This rule adds support for declarations like
        // char *__attribute__((aligned(8))) *f;
        (attribute_specification)=> attribute_specification!
        restrict_declarator[kind, level]
    |
        //{( !(LA(1)==SCOPE||LA(1)==literal_ident) || qualifiedItemIsOneOf(qiPtrMember) )}?
        (ptr_operator)=> ptr_operator // AMPERSAND or STAR
        restrict_declarator[kind, level]
    |   
        (literal_restrict! (tq = cv_qualifier)* )? direct_declarator[kind, level]
    ;

direct_declarator[int kind, int level]
{String id; TypeQualifier tq;}
    :
        // Must be function declaration
        (function_like_var_declarator) =>
        function_like_var_declarator
        {if(kind != declFunctionParam && (kind == declStatement || kind == declNotFirst || LA(1) == COMMA)) {#direct_declarator = #(#[CSM_VARIABLE_LIKE_FUNCTION_DECLARATION, "CSM_VARIABLE_LIKE_FUNCTION_DECLARATION"], #direct_declarator);}}
    |   
        ((ELLIPSIS)? qualified_id LPAREN ~LCURLY) => // Must be class instantiation
        (ELLIPSIS)? id = qualified_id
        {declaratorID(id, qiVar);}
        (variable_attribute_specification)?
        LPAREN
        (expression_list)?
        RPAREN
        {#direct_declarator = #(#[CSM_VARIABLE_DECLARATION, "CSM_VARIABLE_DECLARATION"], #direct_declarator);}
    |
        (options {greedy=true;} : variable_attribute_specification)?
        (
            ((ELLIPSIS)? qualified_id LSQUARE)=>	// Must be array declaration
            (ELLIPSIS)? id = qualified_id 
            {
                 if (_td==true) {
                    declaratorID(id,qiType);
                 } else {
                    declaratorID(id,qiVar);
                 }
                 is_address = false; is_pointer = false;
            }
            (options {warnWhenFollowAmbig = false;}:
             LSQUARE (constant_expression)? RSQUARE)+
            {declaratorArray();}
            {
                if (_td==true) {
                    // todo: build tree in this case
                } else  {
                    #direct_declarator = #(#[CSM_ARRAY_DECLARATION, "CSM_ARRAY_DECLARATION"], #direct_declarator);
                }
            }
        |
            (ELLIPSIS)? id = qualified_id
            {
                 if (_td==true) {
                    // todo: build tree in this case
                    declaratorID(id,qiType);
                 } else {
                    #direct_declarator = #(#[CSM_VARIABLE_DECLARATION, "CSM_VARIABLE_DECLARATION"], #direct_declarator);
                    declaratorID(id,qiVar);
                 }
                 is_address = false; is_pointer = false;
            }
        )
        (options {greedy=true;} :variable_attribute_specification)?
        (asm_block!)?
        (options {greedy=true;} :variable_attribute_specification)?
	|	
		// DW 24/05/04 This block probably never entered as dtor selected out earlier
		//	Note 1: In fact no dictionary entries for ctor or dtor	
		//	Note 2: 2: "class" not recorded in CPPSymbol
		TILDE id = literal_ident {declaratorID(id,qiDtor);}
		{
            if( reportOddWarnings ) printf("direct_declarator[%d]: Warning direct_declarator5 entered unexpectedly with %s\n", LT(1).getLine(),(id));
		}
		LPAREN //{declaratorParameterList(false);}
		(parameter_list[false])?
		RPAREN //{declaratorEndParameterList(false);}
	|	
		LPAREN declarator[kind, level+1] RPAREN
                (options {greedy=true;} :variable_attribute_specification)?
                (
                    {_ts != tsInvalid}?
                        (options {greedy=true;} : declarator_suffixes)?
                |
                    declarator_suffixes
                )   
                (options {greedy=true;} :variable_attribute_specification)?

/* **            
             // Issue #87792  Parser reports error on declarations with name in parenthesis.
                (  (LPAREN | LSQUARE)=> (declarator_suffixes)
                   | 
                ) 
** */
	;

function_like_var_declarator
{String id; TypeQualifier tq;}
    :
        // TODO: refactor the grammar and use function_declarator here
        (options {greedy=true;} :function_attribute_specification)?
        id = idInBalanceParensHard
        {declaratorID(id, qiFun);}
        (variable_attribute_specification)?
        LPAREN //{declaratorParameterList(false);}
        (parameter_list[false])?
        RPAREN //{declaratorEndParameterList(false);}
        (options{greedy = true;} : cv_qualifier_seq)?
        (ref_qualifier)?
        (exception_specification)?
        (trailing_type)?
        (options {greedy = true;} : virt_specifiers)?
        (options {greedy=true;} :function_attribute_specification)?
        (asm_block!)?
        (options {greedy=true;} :function_attribute_specification)?
        (options {greedy=true;} : LITERAL_override | LITERAL_final | LITERAL_new)*                
    ;

declarator_suffixes
	{TypeQualifier tq;}  
	:
	(
		(options {warnWhenFollowAmbig = false;}:
		 LSQUARE (constant_expression)? RSQUARE)+
		{declaratorArray();}
        |
                (LPAREN RPAREN) => declarator_param_list
	|	{(!((LA(1)==LPAREN)&&(LA(2)==IDENT||LA(2)==LITERAL_final))||(qualifiedItemIsOneOf(qiType|qiCtor,1)))}?
		declarator_param_list
//	|	// DW 28/06/04 deleted Assume either following bracketed declaration
//		// empty
	)
	;

/* I think something is weird with the context-guards for predicates;
 * as a result I manually hoist the appropriate pred from ptr_to_member
 *
 * TER: warning: seems that "literal_ident::" will always bypass and go to 2nd alt :(
 */
function_declarator [boolean definition, boolean allowParens, boolean symTabCheck]
    :
        //{( !(LA(1)==SCOPE||LA(1)==literal_ident) || qualifiedItemIsOneOf(qiPtrMember) )}?
        (ptr_operator)=> ptr_operator function_declarator[definition, allowParens, symTabCheck]
    |	
        // int (i);
        {_td || (_ts != tsInvalid) || allowParens}? (LPAREN function_declarator[definition, allowParens, symTabCheck] RPAREN is_post_declarator_token) =>
        LPAREN function_declarator[definition, allowParens, symTabCheck] RPAREN
    |
        function_direct_declarator[definition, symTabCheck] 
    ;

function_direct_declarator [boolean definition, boolean symTabCheck] 
	{String q;}
    :
        (options {greedy=true;} : function_attribute_specification)?
        (function_direct_declarator_2[definition, symTabCheck])

        fun_cv_qualifier_seq

        (options{greedy=true;} : ref_qualifier)?

        (exception_specification)?

        (trailing_type)?

        (options {greedy = true;} : virt_specifiers)?

        //{functionEndParameterList(definition);}
        (( ASSIGNEQUAL ~(LITERAL_default | LITERAL_delete)) => ASSIGNEQUAL OCTALINT)?	// The value of the octal must be 0
        (options {greedy=true;} :function_attribute_specification)?
        (options {greedy=true;} :asm_block!)?
        (options {greedy=true;} :function_attribute_specification)?
    ;
 
protected
is_post_declarator_token
    :
        SEMICOLON | ASSIGNEQUAL | LCURLY | EOF | RPAREN | literal_try
    ;

trailing_type
{int ts = tsInvalid; TypeQualifier tq;}
    :
        POINTERTO 
        cv_qualifier_seq
        ts=trailing_type_specifier
        cv_qualifier_seq
        (options {greedy=true;} : greedy_abstract_declarator)?
    ;

trailing_type_specifier returns [/*TypeSpecifier*/int ts = tsInvalid]
{String id;}
:   
        ts = simple_type_specifier[false]
    |   
        (LITERAL_class|LITERAL_struct|LITERAL_union|LITERAL_enum|LITERAL_typename)
        id = qualified_id
    |
        LITERAL_auto
;

protected
function_direct_declarator_2 [boolean definition, boolean symTabCheck] 
    {String q; CPPParser.TypeQualifier tq;}
    :
    /* predicate indicate that plain literal_ident is ok here; this counteracts any
     * other predicate that gets hoisted (along with this one) that
     * indicates that an literal_ident is a type or whatever.  E.g.,
     * another rule testing isTypeName() alone, implies that the
     * the literal_ident *MUST* be a type name.  Combining isTypeName() and
     * this predicate in an OR situation like this one:
     * ( declaration_specifiers ... | function_declarator ... )
     * would imply that literal_ident can be a type name OR a plain literal_ident.
     */
/*
		(	// fix prompted by (isdigit)() in xlocnum
			LPAREN q = qualified_id { declaratorID(q, qiFun); } RPAREN
		|
			q = qualified_id { declaratorID(q, qiFun);}
		)
*/
        q = idInBalanceParensHard { declaratorID(q, qiFun);}
        (function_attribute_specification)?
        function_parameters[symTabCheck]
    ;

function_parameters [boolean symTabCheck]
    :
    LPAREN
    (
        (LPAREN) => function_parameters[symTabCheck]
    |
        {   //functionParameterList();
            if (K_and_R == false) {
                in_parameter_list = true;
            }
        }
        (parameter_list[symTabCheck])?
        {   if (K_and_R == false) {
                in_parameter_list = false;
            } else {
                in_parameter_list = true;
            }
        }
    )
    RPAREN
    ;

protected
function_params
        :
		LPAREN
		{
		    //functionParameterList();
		    if (K_and_R == false) {
			    in_parameter_list = true;
		    }
		}
		(parameter_list[false])? 
		{
		    if (K_and_R == false) {
	  		in_parameter_list = false;
		    } else {
			in_parameter_list = true;
		    }
		}
		RPAREN
        ;

ctor_definition 
    :
    ctor_head
    (   ctor_body
    |   ASSIGNEQUAL (LITERAL_default | LITERAL_delete)
    )
    //{endConstructorDefinition();}
    ;

ctor_head 
{boolean friend = false; boolean ctorName = false;}
	:
	friend = ctor_decl_spec
	ctorName = ctor_declarator[true]
	;

ctor_decl_spec returns [boolean friend = false]
	:
    ((options {greedy=true;} :function_attribute_specification)|literal_inline|LITERAL_explicit|LITERAL_friend {friend = true;} | LITERAL_constexpr )*
	;

ctor_declarator[boolean definition] returns [boolean isCtor = false]
    :
        (LPAREN ctor_declarator[definition] RPAREN is_post_declarator_token)=>
            LPAREN isCtor = ctor_declarator[definition] RPAREN
        |
            isCtor = ctor_direct_declarator[definition]
    ;   

ctor_direct_declarator[boolean definition] returns [boolean isCtor = false]
    {String q;}
    : 
	// JEL 4/3/96 qualified_id too broad DW 10/06/03 ?
        {isCtor = qualifiedItemIsOneOf(qiCtor);}

	q = qualified_ctor_id
        // VV: 06/06/06 handle constructor of class template explicite specialization
        (LESSTHAN template_argument_list GREATERTHAN)?
	//{declaratorParameterList(definition);}
	LPAREN (parameter_list[false])? RPAREN

        (options{greedy = true;} : cv_qualifier_seq)?

        (ref_qualifier)?

        (exception_specification)?

        (options {greedy = true;} : virt_specifiers)?

	//{declaratorEndParameterList(definition);}
        ((ASSIGNEQUAL OCTALINT) => ASSIGNEQUAL OCTALINT)?
        // IZ 136239 : C++ grammar does not allow attributes after constructor
        (function_attribute_specification)?
    ;

qualified_ctor_id returns [String q = ""]
    :
        LPAREN
        q = qualified_ctor_id                 
        RPAREN
    |
        q = qualified_ctor_direct_id
    ;

// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_direct_id returns [String q = ""]
	{
	    String str;
	    StringBuilder  qitem = new StringBuilder();
	}
	: 
	str = scope_override
	{qitem.append(str);}
	str = literal_ident	// DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
/* ****        
//       Issue 86695 "Parser incorrect build CSM_QUALIFIED_ID branch for templated constructors"

        (options{warnWhenFollowAmbig = false;}:
				 LESSTHAN template_argument_list GREATERTHAN)? 
**** */
	{qitem.append(str);        
	 q = qitem.toString();
	#qualified_ctor_direct_id = #(#[CSM_QUALIFIED_ID, q], #qualified_ctor_direct_id);} 
	;

ctor_body
    :
    (  (ctor_initializer)? compound_statement
    |  function_try_block[true])
    ;

ctor_initializer
	:
	COLON! superclass_init (ELLIPSIS)? (COMMA! superclass_init (ELLIPSIS)? )*

        {#ctor_initializer = #(#[CSM_CTOR_INITIALIZER_LIST, "CSM_CTOR_INITIALIZER_LIST"], #ctor_initializer);}
	;

superclass_init
	{String q;} 
	: 
	q = qualified_id 
        (
            LPAREN (expression_list | array_initializer)? RPAREN
        |
            array_initializer
        )

        {#superclass_init = #(#[CSM_CTOR_INITIALIZER, "CSM_CTOR_INITIALIZER"], #superclass_init);}
	;

dtor_definition
	:
	dtor_head[true]
	dtor_body
	;


dtor_head[boolean definition] 
    {boolean friend;}
    :
        friend = dtor_decl_spec
        dtor_declarator[definition]
    ;

dtor_decl_spec returns [boolean friend = false]
	:
        // TODO: think about flag if destructor is friend
	((options {greedy=true;} :function_attribute_specification)|literal_inline|LITERAL_friend {friend = true;} |LITERAL_virtual)*
	;

/* ********

// Issue 86683 "Parser incorrect build CSM_QUALIFIED_ID branch for destructors"

dtor_declarator[boolean definition]
	:	
	//({definition}? dtor_scope_override)
        dtor_scope_override	
	//{declaratorParameterList(definition);}
        // VV: /06/06/06 ~dtor(void) is valid construction
	LPAREN (LITERAL_void)? RPAREN
        //{declaratorEndParameterList(definition);}
        (ASSIGNEQUAL OCTALINT)?	
	(exception_specification)?        
	;

protected
dtor_scope_override
        {String q; StringBuilder  qitem = new StringBuilder();}
        :
        q = scope_override 
        { qitem.append(q); }
        TILDE 
        id:literal_ident
        (options{warnWhenFollowAmbig = false;}:
				 LESSTHAN template_argument_list GREATERTHAN)?
        { qitem.append('~').append(id.getText()); 
          q = qitem.toString();  
        }        
        { if( q.length() > 0 ) #dtor_scope_override = #(#[CSM_QUALIFIED_ID, q], #dtor_scope_override); } 
        ; 

****** */

dtor_declarator[boolean definition]
    :
        (LPAREN dtor_declarator[definition] RPAREN is_post_declarator_token)=>
            LPAREN dtor_declarator[definition] RPAREN
        |
            dtor_direct_declarator[definition]        
    ;

dtor_direct_declarator[boolean definition]
{String q;}
	:	
	//({definition}? dtor_scope_override)
//        dtor_scope_override
//	TILDE literal_ident
        q = qualified_dtor_id

       (LESSTHAN template_argument_list GREATERTHAN)?
	//{declaratorParameterList(definition);}
        // VV: /06/06/06 ~dtor(void) is valid construction
	LPAREN (LITERAL_void)? RPAREN
        //{declaratorEndParameterList(definition);}
        (options{greedy = true;} : cv_qualifier_seq)?

        (ref_qualifier)?

        (exception_specification)?

        (options {greedy = true;} : virt_specifiers)?

        ((ASSIGNEQUAL OCTALINT) => ASSIGNEQUAL OCTALINT)?

        (options {greedy=true;} :function_attribute_specification)?
	;

qualified_dtor_id returns [String q = ""]
    :
        LPAREN
        q = qualified_dtor_id                 
        RPAREN
    |
        q = qualified_dtor_direct_id
    ;

// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_dtor_direct_id returns [String q = ""]
	{
	    String str;
	    StringBuilder  qitem = new StringBuilder();
	}
	:
	str = scope_override
	{qitem.append(str);}	
    TILDE
    str = literal_ident
    {   
        qitem.append("~");
        qitem.append(str);
        q = qitem.toString();
        #qualified_dtor_direct_id = #(#[CSM_QUALIFIED_ID, q], #qualified_dtor_direct_id);
    }
	;


//protected
//dtor_scope_override
//        {String q;}
//        :
//        q = scope_override
//        { if( q.length() > 0 ) #dtor_scope_override = #(#[CSM_QUALIFIED_ID, q], #dtor_scope_override); }
//        ;

      

dtor_body
	:
	compound_statement
	//{endDestructorDefinition();}
	;

parameter_list [boolean symTabCheck]
	:	
	parameter_declaration_list[symTabCheck] (ELLIPSIS)?
	{ #parameter_list = #(#[CSM_PARMLIST, "CSM_PARMLIST"], #parameter_list); }
	;

parameter_declaration_list [boolean symTabCheck]
	:	
	({!symTabCheck || action.isType(LT(1).getText())}?	parameter_declaration[false]
		(// Have not been able to find way of stopping warning of
		 // non-determinism between alt 1 and exit branch of block
		 COMMA! parameter_declaration[false]
		)*
	)
	;

parameter_declaration[boolean inTemplateParams]
	:	{beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==LITERAL_OPERATOR)) &&
			    (!(LA(1)==SCOPE||LA(1)==IDENT||LA(1)==LITERAL_final) ||
			    qualifiedItemIsOneOf(qiType|qiCtor) )}?
			declaration_specifiers[true, false]	// DW 24/3/98 Mods for K & R
			(  
				(declarator[declFunctionParam, 0])=> declarator[declFunctionParam, 0]        // if arg name given
			| 
				abstract_declarator  // if arg name not given  // can be empty
			)
		|
			(declarator[declOther, 0])=> declarator[declOther, 0]	// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS
		)
		(ASSIGNEQUAL 
                    (   
                        {inTemplateParams}? template_param_expression
                    |
                        array_initializer // c++11 extended initilizer list
                    |	
                        assignment_expression
                    )
		)?
		{ #parameter_declaration = #(#[CSM_PARAMETER_DECLARATION, "CSM_PARAMETER_DECLARATION"], #parameter_declaration); }
	;

simple_parameter_list
    :	
    simple_parameter_declaration
    (COMMA! simple_parameter_declaration)*
    ;

simple_parameter_declaration
    {String s;}
    :
    declaration_specifiers[false, true]
    (s=literal_ident)*
    ;

type_name // aka type_id
	:
	declaration_specifiers[true, false] 
        abstract_declarator
	;

/* This rule looks a bit weird because (...) can happen in two
 * places within the declaration such as "void (*)()" (ptr to
 * function returning nothing).  However, the () of a function
 * can only occur after having seen either a (abstract_declarator)
 * and not after a [..] or simple '*'.  These are the only two
 * valid () func-groups:
 *    int (*)();     // ptr to func
 *    int (*[])();   // array of ptr to func
 */
abstract_declarator
    :	
        ptr_operator (literal_restrict!)? abstract_declarator 
    |
        (abstract_declarator_suffix)+
    |
        (ELLIPSIS) => ELLIPSIS
    |
    ;

/**
 * This rule could be used when nothing goes after it (i.e. parent rule is not anchored).
 * NOTE: it doesn't handle top-level empty alternative
 */
greedy_abstract_declarator
    :
        ptr_operator (literal_restrict!)? (options{greedy = true;} : greedy_abstract_declarator)?
    |
        (options{greedy = true;} : abstract_declarator_suffix)+
    |
        (ELLIPSIS) => ELLIPSIS
    ;

abstract_declarator_suffix
	:	
            LSQUARE (constant_expression)? RSQUARE
            {declaratorArray();}
        |   
            (LPAREN RPAREN) => declarator_param_list
        |
            (LPAREN abstract_declarator RPAREN) => LPAREN abstract_declarator RPAREN
	|
            declarator_param_list
	;

declarator_param_list
    :
        LPAREN
        //{declaratorParameterList(false);}
        (parameter_list[false])?
        RPAREN
        cv_qualifier_seq
        (options{greedy = true;} : ref_qualifier)?
        //{declaratorEndParameterList(false);}
        (exception_specification)?
        (options{greedy = true;} : trailing_type)?
    ;

exception_specification
    {String so;}
    :   LITERAL_throw 
        LPAREN 
        (exception_type_id (COMMA exception_type_id)* )? 
        RPAREN
    |   
        LITERAL_noexcept (options {greedy=true;} : LPAREN constant_expression RPAREN )?
    ;

protected 
virt_specifiers
    :
        (LITERAL_override | LITERAL_final) 
        (options {greedy=true;} : LITERAL_override | LITERAL_final)*
    ;

// simplified version of type_id that is used in exception specification
protected 
exception_type_id
	{ /*TypeSpecifier*/int ts; String so; }
	:
	//( (so = scope_override literal_ident) | built_in_type ) (STAR | AMPERSAND)*
        parameter_declaration[false]
	;

protected
function_attribute_specification! 
        : 
            attribute_specification_list
        ;

protected
variable_attribute_specification!
        :
            attribute_specification_list
        ;

protected
declspec!
        : 
            literal_declspec balanceParens
        ;

protected
type_attribute_specification!
        :
            attribute_specification_list | declspec | LITERAL_alignas balanceParens

        ;

protected
namespace_attribute_specification!
        :
            attribute_specification_list
        ;

protected
attribute_specification_list
	:
	    attribute_specification (options {greedy=true;} : attribute_specification_list)?
	;

attribute_specification
    :
        literal_attribute
        LPAREN balanceParens RPAREN
    |
        ({isCPlusPlus11()}? LSQUARE balanceSquares RSQUARE)
    ;

protected
balanceParens
        : 
            LPAREN
            (options {greedy=false;}:
                balanceParens | .
            )*
            RPAREN
        ;
 
protected    
balanceCurlies
        :
            LCURLY
            // balanceBraces will consume all tokens till the first unbalanced RCURLY
            ({balanceBraces(CPPTokenTypes.LCURLY, CPPTokenTypes.RCURLY)}?) 
            // consume last RCURLY
            (options {greedy=true;} : . )? 
        ;

protected    
balanceSquares
    :
        LSQUARE 
            (options {greedy=false;}:
                balanceSquares | .
            )*
        RSQUARE
    ;

protected    
balanceLessthanGreaterthan
    :
        LESSTHAN 
            (options {greedy=false;}:
                .
            )*
        GREATERTHAN
    ;

// Removed due to restrictions of clone antlr optimization
/*protected 
idInBalanceParensLight returns [String id = ""]
        { int count = 0; }
        :               
            (   LPAREN
                { count++; }
            )*          
            id = qualified_id
            (    RPAREN
                { count--; }
            )*
           {count == 0}?
       ;     */
 
protected
idInBalanceParensHard returns [String id = ""]
        :
             (
                LPAREN
                id = idInBalanceParensHard                 
                RPAREN
              )
              |
              id = qualified_id
        ;

template_head
	:	
               (LITERAL_export!)? 
		LITERAL_template^
		LESSTHAN! tpl:template_parameter_list GREATERTHAN!
		//{ #template_head = #(#[CSM_TEMPLATE_PARMLIST, "CSM_TEMPLATE_PARMLIST"], #tpl); }
	;

template_parameter_list
	:	
		//{beginTemplateParameterList();}
		template_parameter (COMMA template_parameter)*
		//{endTemplateParameterList();}
	;

/* Rule requires >2 lookahead tokens. The ambiguity is resolved 
 * correctly, however. According to the manual "...A template argument
 * that can be interpreted either as a parameter-declaration or a
 * type-argument (because its identifier is the name of an
 * already existing class) is taken as type-argument."
 * Therefore, any "class literal_ident" that is seen on the input, should
 * match the first alternative here (it should be a type-argument).
 */
template_parameter
    {String id = "";}
	:
	(   ((LITERAL_class|LITERAL_typename) (ELLIPSIS)? (literal_ident (ELLIPSIS)? )? (ASSIGNEQUAL | COMMA | GREATERTHAN)) =>
                (LITERAL_class|LITERAL_typename) 
                (ELLIPSIS)? // support for variadic template params
		(id = literal_ident (ELLIPSIS)? )? (ASSIGNEQUAL assigned_type_name)?
		{templateTypeParameter((id == null) ? "" : id);}
	|
		template_template_parameter
	|	
		parameter_declaration[true]	// DW 30/06/03 This doesn't seem to match the
					// current standard
	)
	;

protected template_template_parameter
    {String s;}
    :
    template_head
	LITERAL_class (ELLIPSIS)? (s=literal_ident)? (ASSIGNEQUAL assigned_type_name)?
	{ #template_template_parameter = #(#[CSM_TEMPLATE_TEMPLATE_PARAMETER, "CSM_TEMPLATE_TEMPLATE_PARAMETER"], #template_template_parameter);}

    ;

/* This is to allow an assigned type_name in a template parameter
 *	list to be defined previously in the same parameter list,
 *	as type setting is ineffective whilst guessing
 */
assigned_type_name
	{/*TypeSpecifier*/int ts;
         TypeQualifier tq;
         DeclSpecifier ds = dsInvalid;}
	:
            (options {greedy=true;}: tq=cv_qualifier)? (LITERAL_typename)?
            ts = type_specifier[ds, false] (postfix_cv_qualifier)?
            abstract_declarator
	;

// This rule refers to an instance of a template class or function
template_id	// aka template_class_name
    {String s;}
	:	s=literal_ident LESSTHAN template_argument_list GREATERTHAN
	;

template_argument_list
	:	template_argument (ELLIPSIS)? (COMMA template_argument (ELLIPSIS)? )*
        |    
	;

// lazy_template_argument_list skips types and 
// works faster then template_argument_list,
// but it does not make correct AST.
// It's used in predicates only.
lazy_template_argument_list
	:	
        lazy_template_argument
        (   
            COMMA 
            lazy_template_argument
        )*
	;

lazy_template_argument
    :
        {(isTemplateTooDeep(1, 10))}? 
        (~(GREATERTHAN | LESSTHAN | RCURLY | LCURLY))* 
        (
            lazy_template 
            (~(GREATERTHAN | LESSTHAN | RCURLY | LCURLY | COMMA | ELLIPSIS))*
        )+
    |
        template_param_expression
    ;

/* Here assignment_expression was changed to shift_expression to rule out
 *  x< 1<2 > which causes ambiguities. As a result, these can be used only
 *  by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
 *  x<(1+2)> ==> ok.
 */
template_argument
    {String s;}
    :
        {(isTemplateTooDeep(1, 10))}? 
        (~(GREATERTHAN | LESSTHAN | RCURLY | LCURLY))* 
        (
            lazy_template 
            (~(GREATERTHAN | LESSTHAN | RCURLY | LCURLY | COMMA | ELLIPSIS))*
        )+
    |
        // IZ 167547 : 100% CPU core usage with C++ project.
        // This is check for too complicated tecmplates.
        // If template depth is more then 20 we just skip it.
        ((SCOPE)? (literal_ident SCOPE)* literal_ident templateDepthChecker[20]) => (SCOPE)? (s=literal_ident SCOPE)* s=literal_ident templateDepthChecker[20]
    |
        // IZ 140991 : Parser "hangs" on Loki.
        // This is predicate for fast T<T<...>> pattern recognition.
        ((SCOPE)? (literal_ident SCOPE)* literal_ident simpleBalanceLessthanGreaterthanInExpression (COMMA | GREATERTHAN)) => type_name
    |
        (type_name (COMMA | GREATERTHAN)) => type_name
    |
        template_param_expression
;

lazy_template
    :
        LESSTHAN
        (
            (   ~(GREATERTHAN | LESSTHAN | RCURLY | LCURLY)
            |   lazy_template
            )*
        )
        GREATERTHAN
    ;

templateDepthChecker[int i]
    :
        LESSTHAN
        (
            (   {(i > 0)}? (~(LESSTHAN | GREATERTHAN | RCURLY | LCURLY))*
                templateDepthChecker[i - 1]
                (~(GREATERTHAN | RCURLY | LCURLY))*
            |
                {(i <= 0)}? (   ~(GREATERTHAN | LESSTHAN | RCURLY | LCURLY)
                |   templateDepthChecker[i - 1]
                )*
            )
        )
        GREATERTHAN
    ;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

statement_list
	:	(statement)+
		//{#statement_list = #(#[CSM_STATEMENT_LIST, "CSM_STATEMENT_LIST"], #statement_list);}
	;

single_statement
    :
        (literal_ident COLON) => compound_labeled_statement
    |
        statement
    ;

statement
	{StorageClass sc = scInvalid; int ts = 0;}
	:
	(	
                // Issue 83496   C++ parser does not allow class definition inside function
                ((  storage_class_specifier
		|   cv_qualifier 
		|   LITERAL_typedef
		)* class_head) =>
		{if (statementTrace>=1) 
			printf("statement_1[%d]: Class definition\n",
				LT(1).getLine());
		}
		declaration[declOther]
		{ #statement = #(#[CSM_CLASS_DECLARATION, "CSM_CLASS_DECLARATION"], #statement); }
	|  
                ((  storage_class_specifier
		|   cv_qualifier
		|   LITERAL_typedef
		)* class_forward_declaration) =>
		{if (statementTrace>=1)
			printf("statement_1[%d]: Class forward declaration\n",
				LT(1).getLine());
		}
		declaration[declOther]
		{ #statement = #(#[CSM_GENERIC_DECLARATION, "CSM_GENERIC_DECLARATION"], #statement); }
	|
                // Issue 83996   Code completion list doesn't appear if enum defined within function (without messages)
		// Enum definition (don't want to backtrack over this in other alts)
		((storage_class_specifier)? LITERAL_enum (LITERAL_class | LITERAL_struct)? (literal_ident)? (COLON ts = builtin_cv_type_specifier[ts])? LCURLY)=>
                (sc = storage_class_specifier)?
		{if (statementTrace>=1) 
			printf("statement_2[%d]: Enum definition\n",
				LT(1).getLine());
		}
		enum_specifier (member_declarator_list)? SEMICOLON!	//{end_of_stmt();}
		{ #statement = #(#[CSM_ENUM_DECLARATION, "CSM_ENUM_DECLARATION"], #statement); }
	|
		( LITERAL_typedef ) =>
		// TODO: external_declaration is too generic here. Refactor this!
		external_declaration
	|
                // Function definition in C language
                {isC()}?
                ((LITERAL___extension__)?
                    (options {greedy=true;} :function_attribute_specification!)?
                    declaration_specifiers[false, false]
                    (options {greedy=true;} :function_attribute_specification!)? 
                    function_declarator[true, false, false] LCURLY
                ) =>
                external_declaration {#statement = #(#[CSM_DECLARATION_STATEMENT, "CSM_DECLARATION_STATEMENT"], #statement);} // TODO: refactor this
        |
                { LT(1).getText().equals(LITERAL_EXEC) && LT(2).getText().equals(LITERAL_SQL) }? (literal_ident literal_ident) => pro_c_statement
                {if (statementTrace>=1)
			printf("statement_13[%d]: pro_c_statement\n", LT(1).getLine());
		}
        |
                ( is_known_typename LPAREN literal_ident RPAREN) => // declaration like "int(a);"
                {if (statementTrace>=1) 
                        printf("statement_1a[%d]: declaration\n", LT(1).getLine());
                }
                declaration[declGeneric]  {#statement = #(#[CSM_DECLARATION_STATEMENT, "CSM_DECLARATION_STATEMENT"], #statement);}
        |
                // #227479 - SQL EXEC support is broken
                // This alternative is greedy and must be after pro_c alternative
                ( is_declaration | LITERAL_namespace | literal_inline LITERAL_namespace | LITERAL_static_assert ) =>
                {if (statementTrace>=1) 
			printf("statement_1[%d]: declaration\n", LT(1).getLine());
		}
                declaration[declStatement]  {#statement = #(#[CSM_DECLARATION_STATEMENT, "CSM_DECLARATION_STATEMENT"], #statement);}
	|	
                {if (statementTrace>=1) 
			printf("statement_2[%d]: labeled_statement\n", LT(1).getLine());
		}                
                (literal_ident COLON) => labeled_statement
	|
                {if (statementTrace>=1) 
			printf("statement_3[%d]: case_statement\n", LT(1).getLine());
		}	
                case_statement
	|
                {if (statementTrace>=1) 
			printf("statement_4[%d]: default_statement\n", LT(1).getLine());
		}	
                default_statement
	|
                {if (statementTrace>=1) 
			printf("statement_5[%d]: expression\n", LT(1).getLine());
		}	
                expression SEMICOLON! {/*end_of_stmt();*/#statement = #(#[CSM_EXPRESSION_STATEMENT, "CSM_EXPRESSION_STATEMENT"], #statement);}
	|
                {if (statementTrace>=1) 
			printf("statement_6[%d]: compound_statement\n", LT(1).getLine());
		}	
                compound_statement
	|
                {if (statementTrace>=1) 
			printf("statement_7[%d]: selection_statement\n", LT(1).getLine());
		}	
                selection_statement
	|
                {if (statementTrace>=1) 
			printf("statement_8[%d]: iteration_statement\n", LT(1).getLine());
		}	
                iteration_statement
	|
                {if (statementTrace>=1) 
			printf("statement_9[%d]: jump_statement\n", LT(1).getLine());
		}	
                jump_statement
	|
                {if (statementTrace>=1) 
			printf("statement_10[%d]: SEMICOLON\n", LT(1).getLine());
		}	
                SEMICOLON! //{end_of_stmt();}
	|
                {if (statementTrace>=1) 
			printf("statement_11[%d]: try_block\n", LT(1).getLine());
		}	
                try_block[false]
	|
                {if (statementTrace>=1) 
			printf("statement_13[%d]: asm_block\n", LT(1).getLine());
		}	
                asm_block
//	|	preprocDirective
//        |       member_declaration
)
	;

labeled_statement
    :
    label COLON (options {greedy = true;} : attribute_specification!)? single_statement
    ;

compound_labeled_statement
    :
        labeled_statement
        {#compound_labeled_statement = #([CSM_COMPOUND_STATEMENT, "CSM_COMPOUND_STATEMENT"], #compound_labeled_statement);}
    ;

protected
is_known_typename
{/*TypeSpecifier*/int ts=0;}
    :
        ts=builtin_type[0]
        |
        is_va_list_type
    ;

// This rule should use IDENT instead of literal_ident because in predicates 
// rules don't return values, so contentEquals wouldn't work
protected
is_va_list_type : id:IDENT {"va_list".contentEquals(id.getText())}?; 

protected
label
    {String s;}
	:
	s=literal_ident
	{#label = #([CSM_LABELED_STATEMENT, "CSM_LABELED_STATEMENT"], #label);}
	;

case_statement
	:	LITERAL_case
		case_expression COLON single_statement
	;

default_statement
	:	default_label COLON single_statement
	;

protected
default_label
	:	
	LITERAL_default
		{#default_label = #(#[CSM_DEFAULT_STATEMENT, "CSM_DEFAULT_STATEMENT"], #default_label);}
	;

compound_statement
	:                    
            {isLazyCompound()}? balanceCurlies             
            {#compound_statement = #(#[CSM_COMPOUND_STATEMENT_LAZY, "CSM_COMPOUND_STATEMENT_LAZY"], #compound_statement);}
        |   {!isLazyCompound()}?
            (
                {action.compound_statement(LT(1));}
                LCURLY
		/*{
		    //end_of_stmt();
		    //enterNewLocalScope();
		}*/
		(statement_list)?
                {action.end_compound_statement(LT(1));}
		( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
                | RCURLY )
		//{exitLocalScope();}
		{#compound_statement = #(#[CSM_COMPOUND_STATEMENT, "CSM_COMPOUND_STATEMENT"], #compound_statement);}
            )                      
	;

function_try_block[boolean constructor]
    :
        {isLazyCompound()}?
        literal_try
        ({(constructor)}?((COLON) => ctor_initializer)?)?
        balanceCurlies
        (options {greedy=true;} : 
        (  
            LITERAL_catch LPAREN exception_declaration RPAREN
        |
            literal_finally
        )
        balanceCurlies)*
        {#function_try_block = #(#[CSM_TRY_CATCH_STATEMENT_LAZY, "CSM_TRY_CATCH_STATEMENT_LAZY"], #function_try_block);}
    |
        {!isLazyCompound()}?
        try_block[constructor]
        {#function_try_block = #(#[CSM_COMPOUND_STATEMENT, "CSM_COMPOUND_STATEMENT"], #function_try_block);}
    ;

protected 
condition
    :
        (
            (condition_declaration) => condition_declaration
        |
            condition_expression
        )
        {#condition=#(#[CSM_CONDITION, "CSM_CONDITION"], #condition);}
    ;

protected 
condition_expression
	:
	expression
	;

protected 
condition_declaration {int ts = tsInvalid;}
    :
        declaration_specifiers[true, false]  
        declarator[declStatement, 0]
        (   ASSIGNEQUAL assignment_expression
        |   array_initializer 
        )
    ;

//	(declaration)=> declaration|	expression


/* NOTE: cannot remove ELSE ambiguity, but it parses correctly.
 * The warning is removed with the options statement
 */
selection_statement
	:	
		LITERAL_if LPAREN 
		condition RPAREN
		single_statement
		(options {warnWhenFollowAmbig = false;}:
		 LITERAL_else single_statement)?
		{#selection_statement = #(#[CSM_IF_STATEMENT, "CSM_IF_STATEMENT"], #selection_statement);}
	|	
		LITERAL_switch LPAREN  condition RPAREN single_statement
		{#selection_statement = #(#[CSM_SWITCH_STATEMENT, "CSM_SWITCH_STATEMENT"], #selection_statement);}
	;

iteration_statement
	:
	while_statement | do_while_statement | for_statement
	;

protected
while_statement
	:
		LITERAL_while	
		LPAREN! condition RPAREN! 
		single_statement
		{#while_statement = #(#[CSM_WHILE_STATEMENT, "CSM_WHILE_STATEMENT"], #while_statement);}
	;

protected
do_while_statement
	:
		LITERAL_do 
		single_statement LITERAL_while
		LPAREN! expression RPAREN! 
		( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON ) //{end_of_stmt();}
		{#do_while_statement = #(#[CSM_DO_WHILE_STATEMENT, "CSM_DO_WHILE_STATEMENT"], #do_while_statement);}
	;

protected
for_statement
:
    LITERAL_for LPAREN!
    (
        (for_range_init_statement COLON) =>
        for_range_init_statement COLON (expression | array_initializer)
    |
        for_init_statement
        (
            (condition)? 
            ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
            | SEMICOLON )
            (expression)?
        )?
    )
    RPAREN! single_statement

    {#for_statement = #(#[CSM_FOR_STATEMENT, "CSM_FOR_STATEMENT"], #for_statement);}
;

protected
for_init_statement
:
    (   (declaration[declStatement])=> declaration[declStatement]
    |   expression 
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON ) //{end_of_stmt();}
    |   ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON) //{end_of_stmt();}
    )
    {#for_init_statement = #(#[CSM_FOR_INIT_STATEMENT, "CSM_FOR_INIT_STATEMENT"], #for_init_statement);}
;

protected
for_range_init_statement
:
    declaration_specifiers[true, false] init_declarator[declStatement]
    {#for_range_init_statement = #(#[CSM_FOR_INIT_STATEMENT, "CSM_FOR_INIT_STATEMENT"], #for_range_init_statement);}
;

jump_statement
    {String s;}
	:	
	(	LITERAL_goto 
                ((literal_ident (EOF | SEMICOLON)) => s=literal_ident
                | expression)
                (EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); } |SEMICOLON)
        {/*end_of_stmt();*/ #jump_statement = #(#[CSM_GOTO_STATEMENT, "CSM_GOTO_STATEMENT"], #jump_statement);}
	|	LITERAL_continue (EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); } |SEMICOLON)
        {/*end_of_stmt();*/ #jump_statement = #(#[CSM_CONTINUE_STATEMENT, "CSM_CONTINUE_STATEMENT"], #jump_statement);}
	|	LITERAL_break (EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); } |SEMICOLON)
        {/*end_of_stmt();*/ #jump_statement = #(#[CSM_BREAK_STATEMENT, "CSM_BREAK_STATEMENT"], #jump_statement);}
		// DW 16/05/03 May be problem here if return is followed by a cast expression 
	|	LITERAL_return {in_return = true;}
		(	
                        // VV 22/05/06: commented out alternatives, 
                        // because "return (a)==(b);" incorrectly handled
/*                        
                        options{warnWhenFollowAmbig = false;}:
			(LPAREN {(qualifiedItemIsOneOf(qiType) )}? literal_ident RPAREN)=> 
			LPAREN literal_ident RPAREN (expression)?
			// This is an unsatisfactory fix
			// for problem in xstring re
			// "return (allocator);"
			//  and in xlocale re 
			// "return (_E)(_Tolower((unsigned char)_C, &_Ctype));'
			//{printf("jump_statement[%d]: Return fix used\n",
			//		LT(1).getLine());}
		|	expression 
*/
                (   ((LITERAL___extension__)? cast_array_initializer_head) => initializer
                |   expression
                )
	)?	
        (EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); } |SEMICOLON)
        {in_return = false; /*end_of_stmt();*/ #jump_statement = #(#[CSM_RETURN_STATEMENT, "CSM_RETURN_STATEMENT"], #jump_statement);}
	)
	;

try_block[boolean constructor]
    :
    literal_try
    ({(constructor)}?((COLON) => ctor_initializer)?)?
    compound_statement (options {greedy=true;} : handler)*
    {#try_block = #(#[CSM_TRY_STATEMENT, "CSM_TRY_STATEMENT"], #try_block);}
    ;


handler
	:	
                (  
                    LITERAL_catch LPAREN exception_declaration RPAREN
                |
                    literal_finally
                )
		compound_statement
		{/*exceptionEndHandler();*/{#handler = #(#[CSM_CATCH_CLAUSE, "CSM_CATCH_CLAUSE"], #handler);}}
	;

exception_declaration
	:	parameter_declaration_list[false]
	;

/* This is an expression of type void according to the ARM, which
 * to me means "statement"; it removes some ambiguity to put it in
 * as a statement also.
 */
throw_expression
	:	LITERAL_throw (options {greedy=true;}: assignment_expression) ? 
	;

using_declaration
	{String qid="";}
	:	u:LITERAL_using
		(ns:LITERAL_namespace 
                    {action.using_directive(u, ns);}
                    {if(LA(1) == SCOPE) {action.using_directive(action.USING_DIRECTIVE__SCOPE, LT(1));}} 
                    qid = qualified_id	// Using-directive
                    {action.end_using_directive(LT(0));}
		    {#using_declaration = #[CSM_USING_DIRECTIVE, qid]; #using_declaration.addChild(#u);}
		|
                    {action.using_declaration(u);}
                    {if(LA(1) == SCOPE) {action.using_declaration(action.USING_DECLARATION__SCOPE, LT(1));}} 
                    (LITERAL_typename)?
                    qid = unqualified_id				// Using-declaration
                    {action.end_using_declaration(LT(1));}
		    {#using_declaration = #[CSM_USING_DECLARATION, qid]; #using_declaration.addChild(#u);}
		)
                
		SEMICOLON! //{end_of_stmt();}
	;

alias_declaration
    {String s;}
	:	LITERAL_using
		s=literal_ident ASSIGNEQUAL alias_declaration_type
		SEMICOLON //{end_of_stmt();}
	;

// Rule to catch class definition inside type alias
alias_declaration_type
        :   
            ( 
                // We do not need to process template classes here because of standard.
                // [dcl.type], point 3:
                // A type-specifier-seq shall not define a class or enumeration
                // unless it appears in the type-id of an alias-declaration (7.1.3) that
                // is not the declaration of a template-declaration.  
                (class_head)=>
                    type_name
                    {#alias_declaration_type = #(#[CSM_CLASS_DECLARATION, "CSM_CLASS_DECLARATION"], #alias_declaration_type);}
            |
                (enum_def_head)=>
                    // TODO: think about handling enums via type_name 
                    {if(statementTrace>=1) printf("typedef_enum [%d]\n",LT(1).getLine()); }
                    enum_specifier 
                    (init_declarator_list[declOther])?
                    {#alias_declaration_type = #(#[CSM_ENUM_DECLARATION, "CSM_ENUM_DECLARATION"], #alias_declaration_type);}
            |
                alias_type_name
            )
    ;

alias_type_name
        :
            type_name
            (trailing_type)?
	;

visibility_redef_declaration
{String qid="";}
    :
        qid = qualified_id
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON!) //{end_of_stmt();}
        {#visibility_redef_declaration = #(#[CSM_VISIBILITY_REDEF, qid], #visibility_redef_declaration);}
    ;

asm_block 	
    :
    (
        literal_asm LCURLY (~RCURLY)*
        (EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); } |RCURLY)
    |
        literal_asm (literal_volatile | LITERAL_goto)? ({LA(1)==LPAREN}? balanceParens) // (gcc_asm_expr)* (EOF|RPAREN)
//		{balanceBraces(CPPTokenTypes.LPAREN, CPPTokenTypes.RPAREN);}
    )
    {#asm_block = #(#[CSM_ASM_BLOCK, "CSM_ASM_BLOCK"], #asm_block);}
    ;

static_assert_declaration
    :
        LITERAL_static_assert LPAREN constant_expression COMMA (STRING_LITERAL)+ RPAREN SEMICOLON
    ;

pro_c_statement
    {String s;}
    :
        s=literal_ident s=literal_ident
        (options {greedy=false;}:
                balanceCurlies
            |
                balanceSquaresInExpression
            |
                balanceParensInExpression
            |
                ~(SEMICOLON | RCURLY | LCURLY | LSQUARE | LPAREN | RPAREN)
            |
                (RCURLY | RPAREN)
                { reportError(new NoViableAltException(LT(0), getFilename())); }
        )*
        ( EOF! { reportError(new NoViableAltException(org.netbeans.modules.cnd.apt.utils.APTUtils.EOF_TOKEN, getFilename())); }
        | SEMICOLON!) //{end_of_stmt();}
    ;


///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

expression_list
	:	
        assignment_expression (COMMA assignment_expression)*
	;

expression
	:	
        assignment_expression (COMMA assignment_expression)*
		{#expression = #(#[CSM_EXPRESSION, "CSM_EXPRESSION"], #expression);}
	;

assignment_expression
	:
        (
            // IZ#152872: parser error in VLC on cast expression
            // #191198 -  Parser error in buf.c
            (cast_array_initializer_head)=>cast_array_initializer
            |
            lazy_expression[false, false, 0]
            |
            throw_expression
        )
	(options {greedy=true;}:	
            ( ASSIGNEQUAL              
            | TIMESEQUAL
            | DIVIDEEQUAL
            | MINUSEQUAL
            | PLUSEQUAL
            | MODEQUAL
            | SHIFTLEFTEQUAL
            | SHIFTRIGHTEQUAL
            | BITWISEANDEQUAL
            | BITWISEXOREQUAL
            | BITWISEOREQUAL
            )
            (assignment_expression
            | array_initializer)
        )?
    ;

constant_expression
	:	
		lazy_expression[false, false, 0]
		{#constant_expression = #(#[CSM_EXPRESSION, "CSM_EXPRESSION"], #constant_expression);}
	;

case_expression
	:
        constant_expression
        {#case_expression = #(#[CSM_CASE_STATEMENT, "CSM_CASE_STATEMENT"], #case_expression);}
	;

template_param_expression
    :
        lazy_expression[true, false, 1]
        {#template_param_expression = #(#[CSM_EXPRESSION, "CSM_EXPRESSION"], #template_param_expression);}
    ;

cast_expression
    :
        lazy_expression[false, false, 0]
    ;

// Rule for fast skiping expressions
//
// inTemplateParams - true if we parsing template parameter
// It means that we should stop on GREATERTHAN
//
// searchingGreaterthen - indicates that we are searching '>'
// and have no need to recognize some constructions.
// (IZ 142022 : IDE hangs while parsing Boost)
lazy_expression[boolean inTemplateParams, boolean searchingGreaterthen, int templateLevel]
{/*TypeSpecifier*/int ts=0; String s;}
    :
        (options {warnWhenFollowAmbig = false;}:
            (   OR 
            |   AND 
            |   BITWISEOR 
            |   BITWISEXOR 
            |   AMPERSAND 
            |   NOTEQUAL 
            |   EQUAL
            |   LESSTHAN
            |   LESSTHANOREQUALTO
            |   GREATERTHANOREQUALTO
            |   QUESTIONMARK (expression)? COLON (assignment_expression)
            |   SHIFTLEFT 
            |   SHIFTRIGHT
            |   PLUS 
            |   MINUS
            |   STAR 
            |   DIVIDE 
            |   MOD
            |   DOTMBR 
            |   POINTERTOMBR
            |   PLUSPLUS
            |   MINUSMINUS
            |   DOT
            |   POINTERTO
            |   NOT    
            |   TILDE
            |   ELLIPSIS

            |   balanceParensInExpression (balanceCurlies)? // c99 and c++11 uniform initialization syntax
            |   balanceSquaresInExpression 
                ((lambda_expression_post_capture_predicate) => lambda_expression_post_capture)?
            |   constant

            |   LITERAL_typename
            |   LITERAL___interrupt 
            |   LITERAL___extension__
            |   LITERAL_template
            |   LITERAL_new
            |   LITERAL_delete
            |   LITERAL_this
            |   literal_volatile
            |   literal_const
            |   LITERAL__TYPE_QUALIFIER__
            |   literal_cdecl 
            |   literal_near
            |   literal_far 
            |   literal_pascal 
            |   literal_stdcall
            |   literal_clrcall

            |   ts=builtin_type[0] (options {greedy=true;}: balanceSquaresInExpression)* (balanceCurlies)?

            |   lazy_type_decltype[templateLevel] {ts = tsTYPEID;}

            |   LITERAL_struct
            |   LITERAL_union
            |   LITERAL_class
            |   LITERAL_enum

            |   LITERAL_sizeof
            |   LITERAL___real
            |   LITERAL___imag

            |   LITERAL_alignof
            |   LITERAL___alignof
            |   LITERAL___alignof__

            |   trait_type_literals

            |   LITERAL_auto
            |   LITERAL_override
            |   LITERAL_constexpr
            |   LITERAL_thread_local
            |   LITERAL_static_assert
            |   LITERAL_alignas
            |   LITERAL_noexcept

            |   LITERAL_OPERATOR 
                (options {warnWhenFollowAmbig = false;}: 
                        optor_simple_tokclass
                    |   
                        (literal_volatile|literal_const|LITERAL__TYPE_QUALIFIER__)*
                        (LITERAL_struct | LITERAL_union | LITERAL_class | LITERAL_enum)
                        (options {warnWhenFollowAmbig = false;}: LITERAL_template | s=literal_ident | balanceLessthanGreaterthanInExpression[templateLevel] | SCOPE)+
                        (options {warnWhenFollowAmbig = false;}: lazy_base_close)?
                    |
                        // empty
                )
            |   (LITERAL_dynamic_cast | LITERAL_static_cast | LITERAL_reinterpret_cast | LITERAL_const_cast)
                balanceLessthanGreaterthanInExpression[templateLevel]
            |   {(!inTemplateParams && !searchingGreaterthen)}? (literal_ident balanceLessthanGreaterthanInExpression[templateLevel]) => s=literal_ident balanceLessthanGreaterthanInExpression[templateLevel] (balanceCurlies)?
            |   {(inTemplateParams && !searchingGreaterthen)}? (literal_ident balanceLessthanGreaterthanInExpression[templateLevel] isGreaterthanInTheRestOfExpression[templateLevel]) => s=literal_ident balanceLessthanGreaterthanInExpression[templateLevel] (balanceCurlies)?
            |   SCOPE
            |   s=literal_ident /*{action.id(id);}*/ (options {greedy=true;}: balanceSquaresInExpression)* (balanceCurlies)?
            )
        )+

        ({(!inTemplateParams)}?((GREATERTHAN lazy_expression_predicate) => (GREATERTHAN)+ lazy_expression[false, false, templateLevel])?)?
    ;

lambda_expression_post_capture_predicate
    : 
        (balanceParensInExpression)? 
        (LITERAL_mutable)? 
        (exception_specification)?
        (function_attribute_specification)? 
        (trailing_type)? 
        LCURLY
    ;

lambda_expression_post_capture
    :
        (
            // Lambda function
            (LPAREN (parameter_list[false])? RPAREN)? 
            (LITERAL_mutable)?
            (exception_specification)?
            (function_attribute_specification)? 
            (trailing_type)?
            compound_statement
            {#lambda_expression_post_capture = #(#[CSM_FUNCTION_DEFINITION, "CSM_FUNCTION_DEFINITION"], #lambda_expression_post_capture);}
        )
        {#lambda_expression_post_capture = #(#[CSM_DECLARATION_STATEMENT, "CSM_DECLARATION_STATEMENT"], #lambda_expression_post_capture);}
    ;

// Lazy expression including assignement expressions (like a = b = c;)
protected 
lazy_assignment_expression[boolean inTemplateParams, boolean searchingGreaterthen, int templateLevel]
    :
        lazy_expression[inTemplateParams, searchingGreaterthen, templateLevel]
        (options {greedy=true;}:	
            ( ASSIGNEQUAL              
            | TIMESEQUAL
            | DIVIDEEQUAL
            | MINUSEQUAL
            | PLUSEQUAL
            | MODEQUAL
            | SHIFTLEFTEQUAL
            | SHIFTRIGHTEQUAL
            | BITWISEANDEQUAL
            | BITWISEXOREQUAL
            | BITWISEOREQUAL
            )
            (lazy_expression[inTemplateParams, searchingGreaterthen, templateLevel]
            | array_initializer)
        )*
    ;

protected
isGreaterthanInTheRestOfExpression[int templateLevel]
    :
        (lazy_assignment_expression[true, true, templateLevel])?
        (   COMMA 
            lazy_assignment_expression[true, true, templateLevel]
        )*
        GREATERTHAN
    ;

protected
balanceParensInExpression
{/*TypeSpecifier*/int ts=0; String s;}
        : 
            LPAREN
            (options {greedy=false;}:
                    (literal_ident)=> s=literal_ident (options {greedy=true;}: balanceSquaresInExpression)*
                |
                    (builtin_type[0])=> ts=builtin_type[0] (options {greedy=true;}: balanceSquaresInExpression)*
                |
                    balanceCurlies
                |
                    balanceParensInExpression
                |
                    balanceSquaresInExpression
                    ((lambda_expression_post_capture_predicate) => lambda_expression_post_capture)?
                |
                    ~(SEMICOLON | RCURLY | LCURLY | LPAREN | LSQUARE | RSQUARE)
                |
                    (RCURLY | RSQUARE)
                    { reportError(new NoViableAltException(LT(0), getFilename())); }
            )*
            RPAREN
        ;

protected    
balanceSquaresInExpression
{/*TypeSpecifier*/int ts=0; String s;}
    :
        LSQUARE 
            (options {greedy=false;}:
                    (literal_ident)=> s=literal_ident (options {greedy=true;}: balanceSquaresInExpression)*
                |
                    (builtin_type[0])=> ts=builtin_type[0] (options {greedy=true;}: balanceSquaresInExpression)*
                |
                    balanceCurlies
                |
                    balanceSquaresInExpression
                    ((lambda_expression_post_capture_predicate) => lambda_expression_post_capture)?
                |
                    balanceParensInExpression
                |
                    ~(SEMICOLON | RCURLY | LCURLY | LSQUARE | LPAREN | RPAREN)
                |
                    (RCURLY | RPAREN)
                    { reportError(new NoViableAltException(LT(0), getFilename())); }
            )*
        RSQUARE
    ;

protected    
balanceLessthanGreaterthanInExpression[int templateLevel]
    :
        {(isTemplateTooDeep(templateLevel, 10))}? lazy_template
    |
        // IZ 167547 : 100% CPU core usage with C++ project.
        // This is check for too complicated tecmplates.
        // If template depth is more then 20 we just skip it.
        (templateDepthChecker[20]) => templateDepthChecker[20]
    |
        // IZ 140991 : Parser "hangs" on Loki.
        // This is predicate for fast T<T<...>> pattern recognition.
        (simpleBalanceLessthanGreaterthanInExpression)=> simpleBalanceLessthanGreaterthanInExpression
    |
        LESSTHAN
        (lazy_expression[true, false, templateLevel + 1])?
        (   COMMA
            lazy_expression[true, false, templateLevel + 1]
        )*
        GREATERTHAN
    ;

simpleBalanceLessthanGreaterthanInExpression
    {String s;}
    :
        LESSTHAN
        (   (SCOPE)? (s=literal_ident SCOPE)* s=literal_ident (simpleBalanceLessthanGreaterthanInExpression)?
        |   constant
        )?
        (   COMMA 
            (   (SCOPE)? (s=literal_ident SCOPE)* s=literal_ident (simpleBalanceLessthanGreaterthanInExpression)?
            |   constant
            )
        )*
        GREATERTHAN
    ;

lazy_expression_predicate
{int ts = 0; String s;}
    :
        OR 
    |   AND 
    |   BITWISEOR 
    |   BITWISEXOR 
    |   AMPERSAND 
    |   NOTEQUAL 
    |   EQUAL
    |   LESSTHAN
    |   LESSTHANOREQUALTO
    |   GREATERTHANOREQUALTO
    |   QUESTIONMARK (expression) COLON (assignment_expression)
    |   SHIFTLEFT 
    |   SHIFTRIGHT
    |   PLUS 
    |   MINUS
    |   STAR 
    |   DIVIDE 
    |   MOD
    |   DOTMBR 
    |   POINTERTOMBR
    |   SCOPE
    |   PLUSPLUS
    |   MINUSMINUS
    |   DOT
    |   POINTERTO
    |   NOT    
    |   TILDE

    |   LPAREN
    |   LSQUARE

    |   s=literal_ident

    |   constant

    |   LITERAL___interrupt 
    |   LITERAL___extension__
    |   LITERAL_template
    |   LITERAL_new
    |   LITERAL_delete
    |   LITERAL_this
    |   literal_volatile
    |   literal_const
    |   LITERAL__TYPE_QUALIFIER__
    |   literal_cdecl 
    |   literal_near
    |   literal_far 
    |   literal_pascal 
    |   literal_stdcall
    |   literal_clrcall

    |   ts = builtin_type[0]

    |   LITERAL_OPERATOR 
    |   LITERAL_dynamic_cast 
    |   LITERAL_static_cast 
    |   LITERAL_reinterpret_cast 
    |   LITERAL_const_cast
    |   LITERAL_sizeof
    |   LITERAL___real
    |   LITERAL___imag

    |   LITERAL_alignof
    |   LITERAL___alignof
    |   LITERAL___alignof__

    |   trait_type_literals

    |   LITERAL_auto
    |   LITERAL_override
    |   LITERAL_constexpr
    |   LITERAL_thread_local
    |   LITERAL_static_assert
    |   LITERAL_alignas
    |   LITERAL_noexcept

    |   GREATERTHAN lazy_expression_predicate
    ;

lazy_base_close
    :
        (COLON)
        (options {greedy=false;}:
            .
        )*
        balanceCurlies
    ;

protected
trait_type_literals
    :
        LITERAL___is_pod | LITERAL___has_nothrow_assign | LITERAL___has_nothrow_copy | LITERAL___has_nothrow_constructor |
        LITERAL___has_trivial_assign | LITERAL___has_trivial_copy | LITERAL___has_trivial_destructor | LITERAL___has_virtual_destructor |
        LITERAL___is_abstract | LITERAL___is_empty | LITERAL___is_literal_type | LITERAL___is_polymorphic |
        LITERAL___is_standard_layout | LITERAL___is_trivial | LITERAL___is_union | LITERAL___underlying_type | 
        LITERAL___is_class | LITERAL___is_base_of | LITERAL___has_trivial_constructor
    ;


protected
postfix_cv_qualifier
        :
            ((literal_volatile|literal_const|LITERAL__TYPE_QUALIFIER__) 
                (options {greedy=true;}:unnamed_ptr_operator
                 { #postfix_cv_qualifier=#(#[CSM_PTR_OPERATOR,"CSM_PTR_OPERATOR"], #postfix_cv_qualifier);}
                )*
            )+
        ;

protected
unnamed_ptr_operator
	:	(	AMPERSAND 	{is_address = true;}
                |       AND {is_address = true;} // r-value reference
		|	literal_cdecl 
		|	literal_near
		|	literal_far 
		|	LITERAL___interrupt 
		|	literal_pascal 
		|	literal_stdcall
                |       literal_clrcall
		|	STAR 
		)	
   ;

ptr_operator
	:	(	AMPERSAND 	{is_address = true;}
                |       AND {is_address = true;} // r-value reference
		|	literal_cdecl 
		|	literal_near
		|	literal_far 
		|	LITERAL___interrupt 
		|	literal_pascal 
		|	literal_stdcall
                |       literal_clrcall
		|	ptr_to_member	// e.g. STAR 
		)	
		{#ptr_operator=#(#[CSM_PTR_OPERATOR,"CSM_PTR_OPERATOR"], #ptr_operator);}
   ;

// Match A::B::*
ptr_to_member
	{String s;}
	:
		s = scope_override STAR  {is_pointer = true;} cv_qualifier_seq
	;

// Match the A::B::C:: or nothing
scope_override returns [String s = ""]
    { 
        StringBuilder sitem = new StringBuilder(); 
        String sp = "";
    }
    :
    	(
            SCOPE { sitem.append("::");} 
            (LITERAL_template)? // to support "_Alloc::template rebind<char>::other"
        )?
        (
            (
                (
                        (literal_ident (LESSTHAN (lazy_template_argument_list)? GREATERTHAN)?) 
                    |
                        lazy_type_decltype[0]
                )
                SCOPE                        
            ) => sp = scope_override_part[0]
        )?
        {
            sitem.append(sp);
            s = sitem.toString();
        }
    ;

scope_override_part[int level] returns [String s = ""]
    { 
        StringBuilder sitem = new StringBuilder(); 
        String sp = "";
        String id;
    }
    :
        (
                (
                    id = literal_ident (LESSTHAN template_argument_list GREATERTHAN)? SCOPE
                    {
                        sitem.append(id);
                        sitem.append("::");
                    }
                )
            |
                (
                    type_decltype SCOPE
                    {
                        sitem.append("decltype");
                        sitem.append("::");
                    }
                )
        )
        (LITERAL_template)? // to support "_Alloc::template rebind<char>::other"
        (
            (
                (
                        (literal_ident (LESSTHAN (lazy_template_argument_list)? GREATERTHAN)?) 
                    |
                        lazy_type_decltype[0]
                )
                SCOPE                        
            ) => sp = scope_override_part[level + 1]
        )?   
        {
            sitem.append(sp);
            s = sitem.toString();
        }        
    ;

// lazy_type_decltype skips expression and 
// works faster then type_decltype.
lazy_type_decltype[int templateLevel]
    :
        literal_decltype 
        LPAREN 
        lazy_assignment_expression[false, false, templateLevel] 
        RPAREN
    ;

decltype_expression
        :
        LPAREN expression_list RPAREN
        {#decltype_expression = #(#[CSM_EXPRESSION, "CSM_EXPRESSION"], #decltype_expression);}        
        ;

type_decltype 
    :
        literal_decltype decltype_expression
        {#type_decltype=#(#[CSM_TYPE_DECLTYPE,"CSM_TYPE_DECLTYPE"], #type_decltype);}
    ;

constant
:       OCTALINT
    |   DECIMALINT
    |   HEXADECIMALINT
    |   BINARYINT
    |   CHAR_LITERAL
    |   (options {warnWhenFollowAmbig = false;}: STRING_LITERAL)+
    |   FLOATONE
    |   FLOATTWO
    |   LITERAL_true
    |   LITERAL_false
    |   LITERAL_nullptr
    |   LITERAL___null
    ;

optor 
	:
		LITERAL_new
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE RSQUARE | )		// check syntax
	|   
		LITERAL_delete
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE RSQUARE | )		// check syntax
	|	LPAREN RPAREN
	|	LSQUARE RSQUARE
	|	optor_simple_tokclass	//OPTOR_SIMPLE_TOKCLASS
	;

//Zuo 5/11/2001
// This is the equivalent to "#tokclass OPTOR_SIMPLE_TOKCLASS" in cplusplus.g

optor_simple_tokclass
	:
    (PLUS|MINUS|STAR|DIVIDE|MOD|BITWISEXOR|AMPERSAND|BITWISEOR|TILDE|NOT|
	 SHIFTLEFT|SHIFTRIGHT|
	 ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
	 SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL|
         EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN (options {greedy=true;}: GREATERTHAN)?|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
	 PLUSPLUS|MINUSMINUS|COMMA|POINTERTO|POINTERTOMBR         
	)
	;

/*
// VV: some rules extracted from prev. optor_simple_tokclass, 
// by excluding tokens with several meaning, end grouping other with the same behavior
// i.e STAR could be multiply in expression, but could be dereference pointer,

//Zuo 5/11/2001
// This is the equivalent to "#tokclass OPTOR_SIMPLE_TOKCLASS" in cplusplus.g

optor_simple_tokclass
	:
            expression_unambig_optor
        |
            assign_unambig_optor
        |
            post_cast_unambig_unary_optor
        |
            // ambiguous operators
            (AMPERSAND | STAR | PLUS | MINUS | PLUSPLUS | MINUSMINUS)
	;

// this rule garantees, that on left is not casting for expressions like "(A) optor expr"
protected
expression_unambig_optor
	:
        (DIVIDE|MOD|BITWISEXOR|BITWISEOR|
	 SHIFTLEFT|SHIFTRIGHT|
	 EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
	 COMMA|POINTERTO|POINTERTOMBR
	)
	;

// this rule garantees, that on left is not casting for expressions like "(A) optor expr" 
protected
assign_unambig_optor
	:
        (
	 ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
	 SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL 
	)
	;

// this rule garantees, that on left is casting for expressions like "(A) optor expr"
protected
post_cast_unambig_unary_optor : (TILDE | NOT);
*/


// it's better to have them alphabetically ordered...

protected 
literal_ident returns [String s = ""]
    : 
        id:IDENT 
        {s = id.getText();}
    | 
        kwd:LITERAL_final
        {s = kwd.getText();}
        {#literal_ident = #[IDENT, s];}
    ;

protected
literal_asm : LITERAL_asm|LITERAL__asm|LITERAL___asm|LITERAL___asm__;

protected
literal_cdecl : LITERAL__cdecl|LITERAL___cdecl;

protected
literal_const : LITERAL_const|LITERAL___const|LITERAL___const__;

protected
literal_declspec : LITERAL__declspec|LITERAL___declspec;

protected
literal_far : LITERAL__far|LITERAL___far;

protected
literal_inline : LITERAL_inline | LITERAL__inline | LITERAL___inline | LITERAL___inline__ | LITERAL___forceinline;

protected
literal_int64 : LITERAL__int64|LITERAL___int64;

protected
literal_signed: LITERAL_signed|LITERAL___signed|LITERAL___signed__;

protected
literal_unsigned: LITERAL_unsigned|LITERAL___unsigned__;

protected
literal_near : LITERAL__near|LITERAL___near;

protected
literal_pascal : LITERAL_pascal|LITERAL__pascal|LITERAL___pascal;

protected
literal_stdcall : LITERAL__stdcall|LITERAL___stdcall;

protected
literal_clrcall : LITERAL___clrcall;

protected
literal_volatile : LITERAL_volatile|LITERAL___volatile|LITERAL___volatile__;

protected
literal_typeof : LITERAL_typeof | LITERAL___typeof | LITERAL___typeof__ ;

protected
literal_restrict : LITERAL_restrict | LITERAL___restrict | LITERAL___restrict__;

protected
literal_complex : LITERAL__Complex | LITERAL___complex__ | LITERAL___complex;

protected
literal_attribute : LITERAL___attribute | LITERAL___attribute__;

protected
literal_try : LITERAL_try | LITERAL___try;

protected
literal_finally : LITERAL___finally;

protected
literal_decltype : LITERAL_decltype | LITERAL___decltype;

